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.

  • thankful

    Brilliant. I’ve been looking for something like this for ages! Clear explanation and simple code that works.
    Thank you.

  • thankful

    Brilliant. I’ve been looking for something like this for ages! Clear explanation and simple code that works.
    Thank you.

  • Pingback: ARTbird309’s Blog » Article » links for 2006-09-02

  • ali

    there is an error in while($result = mysql_fetch_array($doGet)){

  • ali

    there is an error in while($result = mysql_fetch_array($doGet)){

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

    would you be helpful and point out where the error is ali? the last block of code is fine, although the first block did have the wrong variable name.

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

    would you be helpful and point out where the error is ali? the last block of code is fine, although the first block did have the wrong variable name.

  • http://www2.science.tamu.edu/news.xml Kendra Beasley

    Something in my code is not validating. Can you help? (http://www2.science.tamu.edu/news.xml)

    Seems like the first line in most RSS feeds is something like:

    Do you think this is the problem? Or is this covered by that one header line:

    Any help is appreciated.

  • http://www2.science.tamu.edu/news.xml Kendra Beasley

    Something in my code is not validating. Can you help? (http://www2.science.tamu.edu/news.xml)

    Seems like the first line in most RSS feeds is something like:

    Do you think this is the problem? Or is this covered by that one header line:

    Any help is appreciated.

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

    Hey Kendra, it looks like your code didn’t come through.

    What error are you getting when you try to validate it?

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

    Hey Kendra, it looks like your code didn’t come through.

    What error are you getting when you try to validate it?

  • http://brad.globeproductions.com.au/ bard

    Wow, you’re my total hero.

    Thanks so very much for this quick and

  • http://brad.globeproductions.com.au bard

    Wow, you’re my total hero.

    Thanks so very much for this quick and

  • http://brad.globeproductions.com.au/ bard

    Wow, you?¢‚Ǩ‚Ñ¢re my total hero.

    Thanks so very much for this quick and EASY tutorial. Worked a treat, and had me up and running in no time.

    Going to use this to submit my site to http://gnoos.com.au.

    I’m so ultra-stoked at home easy this was.

    cheers!

  • http://brad.globeproductions.com.au bard

    Wow, you?¢‚Ǩ‚Ñ¢re my total hero.

    Thanks so very much for this quick and EASY tutorial. Worked a treat, and had me up and running in no time.

    Going to use this to submit my site to http://gnoos.com.au.

    I’m so ultra-stoked at home easy this was.

    cheers!

  • http://brad.globeproductions.com.au/ bard

    PS – I didn’t need the (very clever) .htaccess trick. I simply created a new directory under the docroot called “feed” and created the script I adapted from your methods as “index.php”. Thus: The feed url is http://brad.globeproductions.com.au/feed ;)

    Just a tip!

  • http://brad.globeproductions.com.au bard

    PS – I didn’t need the (very clever) .htaccess trick. I simply created a new directory under the docroot called “feed” and created the script I adapted from your methods as “index.php”. Thus: The feed url is http://brad.globeproductions.com.au/feed ;)

    Just a tip!

  • http://www.emergeworship.com/ Don

    Hey, thanks so much for your help, but somehow I’m still missing something…I’m coding this in DreamWeaver and my site is hosted on godaddy.com…the RSS feed, as you will soon see, is tailored for iTunes…My code is below…could you please take a look at it and email me back?? I’d really apprecaite it…

    [code]

    Emerge Worship
    http://www.emergeworship.com/Podcasts/
    Emerge, a college and young adult worship service where people from different backgrounds and churches throughout the Dallas area can come together and worship. http://www.emergeworship.com
    en-us
    Emerge Worship

    length= type="/>

    no

    Emerge Worship
    dsartain@emergeworship.com

    [/code]

  • http://www.emergeworship.com Don

    Hey, thanks so much for your help, but somehow I’m still missing something…I’m coding this in DreamWeaver and my site is hosted on godaddy.com…the RSS feed, as you will soon see, is tailored for iTunes…My code is below…could you please take a look at it and email me back?? I’d really apprecaite it…

    [code]

    Emerge Worship
    http://www.emergeworship.com/Podcasts/
    Emerge, a college and young adult worship service where people from different backgrounds and churches throughout the Dallas area can come together and worship. http://www.emergeworship.com
    en-us
    Emerge Worship

    length= type="/>

    no

    Emerge Worship
    dsartain@emergeworship.com

    [/code]

  • http://www.emergeworship.com/ Don

    well that didn’t work at all, did it! If you could please email me I’ll just send you the file…if you have time…

  • http://www.emergeworship.com Don

    well that didn’t work at all, did it! If you could please email me I’ll just send you the file…if you have time…

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

    Sorry Don, I can’t provide technical support. I don’t know the particulars of your set up., so I can’t be of much help.

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

    Sorry Don, I can’t provide technical support. I don’t know the particulars of your set up., so I can’t be of much help.

  • http://www.ananblog.co.uk/ Anan. O.

    There is an error for some ppl. becos of ur MySQL version.

    Instead of

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

    The Limit clause should be normally at the end of the SQL statement:

    ;o)

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

  • http://www.ananblog.co.uk Anan. O.

    There is an error for some ppl. becos of ur MySQL version.

    Instead of

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

    The Limit clause should be normally at the end of the SQL statement:

    ;o)

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

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

    Thanks Anan. This tutorial used MySQL 3.2 or something … I’ll get around to updating it soon.

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

    Thanks Anan. This tutorial used MySQL 3.2 or something … I’ll get around to updating it soon.

  • http://www.emergeworship.com/ Don

    $query=”SELECT s.speaker, r.cast_id, r.title, r.filename, r.description, r.pubDate, r.size FROM `speakers` as s INNER JOIN `RSS_info` as r ON s.speaker_id=r.speaker_id;”

    Is my query statement…I’m running MySQL 5.0…or something like that…I don’t see where that would be an issue though…all I get when I test it and view the source are open and close HTML tags, with nothing in the middle…

  • http://www.emergeworship.com Don

    $query=”SELECT s.speaker, r.cast_id, r.title, r.filename, r.description, r.pubDate, r.size FROM `speakers` as s INNER JOIN `RSS_info` as r ON s.speaker_id=r.speaker_id;”

    Is my query statement…I’m running MySQL 5.0…or something like that…I don’t see where that would be an issue though…all I get when I test it and view the source are open and close HTML tags, with nothing in the middle…

  • http://www.emergeworship.com/ Don

    I figured out what it was, thanks so much!

  • http://www.emergeworship.com Don

    I figured out what it was, thanks so much!

  • Andrew

    Thanks for the awesome code, I’ve used it before and it’s perfect.

    I’ve tried doing it again on a different setup, and I’m having issues. Basically I’m getting parsing errors as it is not recognising the PHP tags. I have put the .htaccess file up (which is the exact same as the one I used to use!), and it doesn’t seem to be recognising it.

    Is there any instances where the .htaccess file wouldn’t work, or perhaps overridden globally?

    thanks!

    ps, the feed is here:

    http://s05.webdev.stir.ac.uk/rss/rss.xml

  • Andrew

    Thanks for the awesome code, I’ve used it before and it’s perfect.

    I’ve tried doing it again on a different setup, and I’m having issues. Basically I’m getting parsing errors as it is not recognising the PHP tags. I have put the .htaccess file up (which is the exact same as the one I used to use!), and it doesn’t seem to be recognising it.

    Is there any instances where the .htaccess file wouldn’t work, or perhaps overridden globally?

    thanks!

    ps, the feed is here:

    http://s05.webdev.stir.ac.uk/rss/rss.xml

  • Pingback: Royal Books « Tech Ramblings from the Rare Book Trade

  • http://www.onlineflashgames.org/ gent00

    Awesome code!thanks

  • http://www.onlineflashgames.org gent00

    Awesome code!thanks

  • http://www.nima.com.mx/ mexman

    OK checare este para ver que tal funciona. Gracias

    Mexman

  • http://www.nima.com.mx mexman

    OK checare este para ver que tal funciona. Gracias

    Mexman

  • AP

    Thanks for the code. It is very helpful.

  • AP

    Thanks for the code. It is very helpful.

  • http://www.stormlakeradio.com/localfeed.xml Synomen

    The question: Why use RSS feeds?
    I stumbled across your article in my efforts to build a dynamic web page for local news. As I was explaining my findings, the question came up “Why RSS feeds?” Why not just pull the information dynamically to my PHP page and scroll through the headlines using java scripting?
    I excited with what I’ve been able to accomplish with RSS feeds from national sites like ABC but isn’t this a bit rich for local news headlines?
    Thanks for your contribution and input!

  • http://www.stormlakeradio.com/localfeed.xml Synomen

    The question: Why use RSS feeds?
    I stumbled across your article in my efforts to build a dynamic web page for local news. As I was explaining my findings, the question came up “Why RSS feeds?” Why not just pull the information dynamically to my PHP page and scroll through the headlines using java scripting?
    I excited with what I’ve been able to accomplish with RSS feeds from national sites like ABC but isn’t this a bit rich for local news headlines?
    Thanks for your contribution and input!

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

    Simply put: RSS puts the reader in control. RSS feeds can be used to create an aggregator page, or on a customized homepage. If you want to share headlines across a network of sites, RSS can do that.

    If you want to create a branded widget for Yahoo! Widget Engine or Mac OS X Dashboard, you can use RSS to serve those headlines.

    Yes, you could use JavaScript, but then what can your user do with it in that form? They still have to remember to visit your web site in order to see your headlines. With RSS, they subscribe once and everything goes to their aggregator.

    It’s really a matter of what you’d like people to receive your data: make them come to you, or deliver it right to them.

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

    Simply put: RSS puts the reader in control. RSS feeds can be used to create an aggregator page, or on a customized homepage. If you want to share headlines across a network of sites, RSS can do that.

    If you want to create a branded widget for Yahoo! Widget Engine or Mac OS X Dashboard, you can use RSS to serve those headlines.

    Yes, you could use JavaScript, but then what can your user do with it in that form? They still have to remember to visit your web site in order to see your headlines. With RSS, they subscribe once and everything goes to their aggregator.

    It’s really a matter of what you’d like people to receive your data: make them come to you, or deliver it right to them.

  • Cindreta

    can you please help whenever i try the feed and look at the code it says there that Supplied argument is not a valid MySQL result resource, and he points to a line where there is
    while($result = mysql_fetch_array( $do )) {

    what’s rong here can someone please help me

  • Cindreta

    can you please help whenever i try the feed and look at the code it says there that Supplied argument is not a valid MySQL result resource, and he points to a line where there is
    while($result = mysql_fetch_array( $do )) {

    what’s rong here can someone please help me

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

    Supplied argument is not a valid MySQL result resource

    this error means that the variable you’re using in mysql_fetch_array() is not the variable name in which your mysql_query is being stored.

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

    Supplied argument is not a valid MySQL result resource

    this error means that the variable you’re using in mysql_fetch_array() is not the variable name in which your mysql_query is being stored.

  • antimatty

    Cindreta, I am guessing that the error you are seeing means that your SQL statement is not working, so the variable ‘$do’ has the value false, instead of being a valid MySQL result set.

    Check that you put the SQL in correctly, and check that your database is set up correctly. Test the SQL with your database but using a MySQL client instead of via PHP – that will tell you whether the problem is with the PHP code, or with the database and SQL.

    Good luck!

  • antimatty

    Cindreta, I am guessing that the error you are seeing means that your SQL statement is not working, so the variable ‘$do’ has the value false, instead of being a valid MySQL result set.

    Check that you put the SQL in correctly, and check that your database is set up correctly. Test the SQL with your database but using a MySQL client instead of via PHP – that will tell you whether the problem is with the PHP code, or with the database and SQL.

    Good luck!