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.lankaenews.com Manoj

    (“SELECT id,tittle,short_s,rank FROM news WHERE place=\”in\” AND pos=\”bar\” ORDER BY rank DESC “);

    get some error

  • [manuel]

    Do anyone else realizes that nowadays the web is becoming a simpler universe? years ago to do anything you have to read read code code and study and burn eyebrows a lot; but now, technology is simplifying itself to the point where things are already done and you just call them (oop) and mixing ingredients sorts out the most exquisit electronic dishes. awesome!!!

  • http://notyet... [manuel]

    Do anyone else realizes that nowadays the web is becoming a simpler universe? years ago to do anything you have to read read code code and study and burn eyebrows a lot; but now, technology is simplifying itself to the point where things are already done and you just call them (oop) and mixing ingredients sorts out the most exquisit electronic dishes. awesome!!!

  • http://www.adiulici.com/ Adi Ulici

    Thank you!!!
    I was searching this for a looooong time, finally!
    Thanks allot for the script!

  • http://www.adiulici.com/ Adi Ulici

    Thank you!!!
    I was searching this for a looooong time, finally!
    Thanks allot for the script!

  • bipi

    how to connect to database??

  • bipi

    how to connect to database??

  • http://mayuonline.com/eblog mayooresan

    I was trying with your code, and my problem is…

    In firefox..

    RSS page is cumn.. but it doesn’t show any content.. only the heading is cumming…!!! what could be the wrong.. I edited the query according to my table structure…

    in IE 7
    Internet Explorer cannot display this feed

    This feed contains code errors.

    what could be the problem??

    my query is:SELECT mesgID,title,content,UNIX_TIMESTAMP(date) AS pubDate
    FROM mesgboard ORDER BY date DESC LIMIT 0, 5;

  • http://mayuonline.com/eblog mayooresan

    I was trying with your code, and my problem is…

    In firefox..

    RSS page is cumn.. but it doesn’t show any content.. only the heading is cumming…!!! what could be the wrong.. I edited the query according to my table structure…

    in IE 7
    Internet Explorer cannot display this feed

    This feed contains code errors.

    what could be the problem??

    my query is:SELECT mesgID,title,content,UNIX_TIMESTAMP(date) AS pubDate
    FROM mesgboard ORDER BY date DESC LIMIT 0, 5;

  • Jordan Crocker

    @bipi: Research before you ask ;)

    http://www.php.net/mysql_connect&quot;

    Great tut, will be implementing soon!

  • Jordan Crocker

    @bipi: Research before you ask ;)

    http://www.php.net/mysql_connect&quot;

    Great tut, will be implementing soon!

  • Jonathan Thomas

    Hi, excellent stuff, I’ve been wanting to do this for a while, thank you for your code.

    I’m in the process of designing a complex database driven website and was wondering if there is a way to get data from a "latest news" table and also from a "weekly tv listings" table.

    The idea being that when news is updated on the site, the RSS shows the update, but also the RSS would hopefully show the latest TV listings for programs in the tv listings table as and when they are updated.

    There are different fields in each table and the structure of each is different.

    Can this be achieved? The field names are different in each table and there are more fields in one than the other so I’m assuming there’d be some kind of PHP statement in there that gets the latest posts from either of the tables?

    Please help! :)

    Many thanks
    Jonathan

  • http://www.satellitecitytv.net,www.jonathanpthomas.com&www.jonathanpthomas.com/thebroomcupboard Jonathan Thomas

    Hi, excellent stuff, I’ve been wanting to do this for a while, thank you for your code.

    I’m in the process of designing a complex database driven website and was wondering if there is a way to get data from a "latest news" table and also from a "weekly tv listings" table.

    The idea being that when news is updated on the site, the RSS shows the update, but also the RSS would hopefully show the latest TV listings for programs in the tv listings table as and when they are updated.

    There are different fields in each table and the structure of each is different.

    Can this be achieved? The field names are different in each table and there are more fields in one than the other so I’m assuming there’d be some kind of PHP statement in there that gets the latest posts from either of the tables?

    Please help! :)

    Many thanks
    Jonathan

  • http://www.ideiasedesafios.com/ Jose Almeida

    Hi,

    I’m looking for a PHP programer to develop and RSS2.0 feed for my site.

    Anyone interested in doing it?

    This is a paid job.

    Regards,
    Jose

  • http://www.ideiasedesafios.com Jose Almeida

    Hi,

    I’m looking for a PHP programer to develop and RSS2.0 feed for my site.

    Anyone interested in doing it?

    This is a paid job.

    Regards,
    Jose

  • http://www.forum.studio2webdesign.com/index.php Web Design Forum

    This is a very good method and I’ll be using it for a gallery website that is compatible with Piclens.

    The XML will be automatically generated when a new image is submitted and published after being checked.

  • http://www.forum.studio2webdesign.com/index.php Web Design Forum

    This is a very good method and I’ll be using it for a gallery website that is compatible with Piclens.

    The XML will be automatically generated when a new image is submitted and published after being checked.

  • http://www.tutorialwave.com/ Josh

    Nice tutorial. Do you mind if i add this to my tutorial site? (www.tutorialwave.com)

  • http://www.tutorialwave.com Josh

    Nice tutorial. Do you mind if i add this to my tutorial site? (www.tutorialwave.com)

  • http://www.peuteren.nl/peuters Martin Smits

    Hi,

    First of all thanks for the code.
    I very good understandable even for a Dutchman.
    I however, get the errer that it isn’t allowed to place a space after
    The error appears on the first line between and header

    Can you plse help me?

    Kind regards,

    Martin Smits

  • http://www.peuteren.nl/peuters Martin Smits

    Hi,

    First of all thanks for the code.
    I very good understandable even for a Dutchman.
    I however, get the errer that it isn’t allowed to place a space after
    The error appears on the first line between and header

    Can you plse help me?

    Kind regards,

    Martin Smits

  • Pingback: Hvordan lage feed? - Webforumet.no - Webmaster forum

  • http://www.flashgamerecipes.com/ Gedas

    PHP code will be displayed if htaccess fails, so for extra security i recommend to:
    *use SQL login with read rights only
    *put DB connection code in another php file (DB.php) and include it to rss.xml via include(‘DB.php’), only ‘include(‘DB.php’)’ will be displayed protecting your login.

  • http://www.flashgamerecipes.com Gedas

    PHP code will be displayed if htaccess fails, so for extra security i recommend to:
    *use SQL login with read rights only
    *put DB connection code in another php file (DB.php) and include it to rss.xml via include(‘DB.php’), only ‘include(‘DB.php’)’ will be displayed protecting your login.

  • teo

    it's impossible för me to add the result as an google gadget, "Error parsing module spec: Not a properly formatted file missing xml header. " i think what they are asking for is <xml version="1.0">, but it seems impossible to this otherwise gread script…

  • teo

    it's impossible för me to add the result as an google gadget, "Error parsing module spec: Not a properly formatted file missing xml header. " i think what they are asking for is <xml version="1.0">, but it seems impossible to this otherwise gread script…

  • ahmed

    thanks
    i found this very helpful.

  • ahmed

    thanks
    i found this very helpful.

  • http://balilestari.com/ bali blog

    Great tutorial..thank you!

  • http://balilestari.com bali blog

    Great tutorial..thank you!

  • http://www.walkinginsqaures.com/ WIS

    This tutorial is absolutely amazing, thank you so much for sharing – I've been looking for something like this a long time.

  • http://www.walkinginsqaures.com WIS

    This tutorial is absolutely amazing, thank you so much for sharing – I've been looking for something like this a long time.

  • http://www.ankitsabharwal.com/ ankit

    possibly the simplest way !! thanks !!

  • http://www.ankitsabharwal.com ankit

    possibly the simplest way !! thanks !!

  • http://www.sagarsoftwares.co.cc/ Kunal Sagar

    Thanks a lot
    this was helpful
    :)

  • http://www.sagarsoftwares.co.cc Kunal Sagar

    Thanks a lot
    this was helpful
    :)

  • https://tubutas.gotdns.com/t_blog Tubutas

    http://blogs.law.harvard.edu/tech/rss/

    The link to that site doesn't work =

  • https://tubutas.gotdns.com/t_blog Tubutas

    http://blogs.law.harvard.edu/tech/rss/

    The link to that site doesn't work =