PHP Universal Feed Generator (supports RSS 1.0, RSS 2.0 and ATOM)

It’s been a while since I’ve planned on developing a RSS writer that fulfills most my needs by supporting the various feed formats. Although the necessity was the prime force behind it, a discussion with Hasin and Emran has put the actual fire in. We were discussing about what can be added next in the Orchid – “PHP framework for the rest of us” and suddenly it hit me. At last, it’s finally complete and I’ve named it “PHP Universal Feed Generator“, as it generates both ATOM and RSS feeds.

Supported versions:

  • RSS 1.0 (which officially obsoleted RSS 0.90)
  • RSS 2.0 (which officially obsoleted RSS 0.91, 0.92, 0.93 and 0.94)
  • ATOM 1.0

Download:

Features:

  • Generates RSS 1.0, RSS 2.0 and ATOM 1.0 feeds
  • All feeds are are validated by feed validator.
  • Supports all possible feed elements.
  • Simple and easy to define channel and feed items
  • Implements appropriate namespaces for different versions.
  • Automatically converts date formats.
  • Generates UUID for ATOM feeds.
  • Enables usage of subtags and attributes. (example: image and encloser tags)
  • Completely Object oriented in PHP5 class structure.
  • Handles CDATA encoding for required tags.
  • Nearly same code for generating all kinds of feed

A minimum example

It’s a minimum example of using this class. I am generating a RSS 2.0 feed from retrieved data from a MySQL database. There are more examples in the download package for different versions.

<?php
  <span style="color: #008000;">// This is a minimum example of using the Universal Feed Generator Class</span>
  include(<span style="color: #006080;">"FeedWriter.php"</span>);

  <span style="color: #008000;">//Creating an instance of FeedWriter class. </span>
  $TestFeed = <span style="color: #0000ff;">new</span> FeedWriter(RSS2);

  <span style="color: #008000;">//Setting the channel elements</span>
  <span style="color: #008000;">//Use wrapper functions for common channel elements</span>
  $TestFeed-&gt;setTitle(<span style="color: #006080;">'Testing &amp; Checking the RSS writer class'</span>);
  $TestFeed-&gt;setLink(<span style="color: #006080;">'http://www.ajaxray.com/projects/rss'</span>);
  $TestFeed-&gt;setDescription(<span style="color: #006080;">'This is test of creating a RSS 2.0 feed Universal Feed Writer'</span>);

  <span style="color: #008000;">//Image title and link must match with the 'title' and 'link' channel elements for valid RSS 2.0</span>
  $TestFeed-&gt;setImage(<span style="color: #006080;">'Testing the RSS writer class'</span>,<span style="color: #006080;">'http://www.ajaxray.com/projects/rss'</span>,<span style="color: #006080;">'http://www.rightbrainsolution.com/images/logo.gif'</span>);

    <span style="color: #008000;">//Retriving informations from database</span>
    mysql_connect("server", "mysql_user", "mysql_password");
    mysql_select_db("my_database");

$result = mysql_query(“Your query here”);

 

    <span style="color: #0000ff;">while</span>($row = mysql_fetch_array($result, MYSQL_ASSOC))
    {
        <span style="color: #008000;">//Create an empty FeedItem</span>
        $newItem = $TestFeed-&gt;createNewItem();

        <span style="color: #008000;">//Add elements to the feed item    </span>
        $newItem-&gt;setTitle($row[<span style="color: #006080;">'title'</span>]);
        $newItem-&gt;setLink($row[<span style="color: #006080;">'link'</span>]);
        $newItem-&gt;setDate($row[<span style="color: #006080;">'create_date'</span>]);
        $newItem-&gt;setDescription($row[<span style="color: #006080;">'description'</span>]);

        <span style="color: #008000;">//Now add the feed item</span>
        $TestFeed-&gt;addItem($newItem);
    }

  <span style="color: #008000;">//OK. Everything is done. Now genarate the feed.</span>
  $TestFeed-&gt;genarateFeed();
?&gt;

Shhhh….a universal feed reader is on the way 😉

196 Comments

  1. Hello there.

    Did a quick look and I have a few comments:
    – It should be “generateFeed” and not “genarateFeed”
    – The constants would be better as class constants imho
    – The __autoload has nothing to do there and will be annoying for people using your code (they’ll have to remove it)
    – (Almost) everything private should be protected instead to allow for inheritance
    – What is the license? It’s not written anywhere
    – I’m not very fan of all these concatenation, 3 template files (1 for each type of feed) could be clearer and less bug-prone

    Good work.

  2. Hey there,

    Just wanted to let you know that you should test your site in Safari, because the whole main body container is flipping to the left out of alignment with the header container. Its also noticeable on Firefox, although its not nearly as bad as Safari.

    Great post by the way.

  3. I do not find if this is not the best code, the main thing is that it works! Thank you very much Loic when you do some developments let us know to check if you create code as you criticise

  4. @Loïc Hoguin:
    Thanks a lot for your suggestion. I’ll modify it soon as your comment.
    When the createNewItem() function is called, the __autoload() function loads the FeedItem class from FeedItem.php file.
    Thanks you again.

  5. @Jake Rutter:
    Thanx for you comment.
    I’ve tested the site in safari 3.0.4 and no problem found there. Can you plz tell me about your Safari version?

  6. Yes, the __autoload is there for loading the item class, but what I was trying to point out was that if I include your feed generator while already having an __autoload in my project, it’ll die because the __autoload function already exist. So I would have to remove that part.

    But that’s just a small annoyance, don’t worry about it too much. 🙂

    Have fun polishing it!

  7. @Romain:
    Hi friend,
    Thanks for your comment.
    There is no need to have a separate file with .xml extension. When you call the generateFeed() function, it sets the header Content-type as “text/xml”. So, the browser handle the output as an XML file.

  8. Anis vai,

    I’ve tested the examples and found the following error

    http://localhost/feedwriter/example_minimum.php

    Fatal error: Call to a member function query() on a non-object in C:apachefriendsxampphtdocsfeedwriterexample_minimum.php on line 18

    Would you please check out this.

    By the way, all the things are appreciatable. But I’ve two suggestions for you.
    1) FeedWriter.php: In function startItem (line 398) you’ve used die. But anyone may want to handle exception according to his/her necessities. So, throw new Exception() should be used here.
    2) FeedWriter.php: You’ve used echo in several functions to generate Feed. But I think it would be better if you assign all the echos in a string and return the string to the caller. As for example, anyone can write echo $TestFeed->genarateFeed(); (See example_rss1.php line 44).

    Thanks.

  9. @Mohammad Jahedur Rahman :
    Jahid vai,
    Thanks for your comment.
    Here the “$db->query()” is just an example of using.
    There is no database connection and no $db class in this script.
    You have to re-write this data collecting portion yourself as your database.

    I’ll keep in mind your suggestions and try to implement in next version.

  10. it gots some problems with chinese character.
    SO I modify some source code.
    In Line 298

    htmlentities($tagContent);
    switch
    htmlentities($tagContent, ENT_COMPAT, ‘utf-8’);

    In Line 82
    header(“Content-type: text/xml”);
    switch to
    header(“Content-type: text/xml; charset=UTF-8”);

  11. It got some problems with chinese character.
    so I modify some source code.
    at Line 298

    change htmlentities($tagContent);
    to
    htmlentities($tagContent, ENT_COMPAT, ‘utf-8′);

    at Line 82
    change
    header(”Content-type: text/xml”);
    to
    header(”Content-type: text/xml; charset=UTF-8″);

    that’s it

  12. how do I link it to the mysql DB? I cannot make sense about that? How do I pass the user/pass and select with dB/tables to query? Could you please explain that a lil bit more?
    Thanks! great script!

  13. @sergio:
    Hi friend,
    U and some of others were confused at this portion.
    So, I’ve changed it.
    Hope it will be easier now to understand how to collect informations from db and use with this class.

    Thanks a lot.

  14. it can run in php4 ??!!
    because run in php5 is ok
    but php5 have an error


    Parse error: syntax error, unexpected T_STRING, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ‘}’ in /www/history/FeedWriter/FeedWriter.php on line 20

  15. Like Kereste says (1. June) FeedWrite makes problems with some none-english utf-8 characters like ä etc.. this is because xml only knows 5 entities (&,”,’,). So I changed line 298 in the source code into

    $nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : str_replace ( array ( ‘&’, ‘”‘, “‘”, ” ), array ( ‘&’ , ‘"’, ‘'’ , ‘<‘ , ‘>’ ), $tagContent);

    to avoiod converting charakters into wrong xml entities.

  16. Hello.
    I had a problem with feedwriter, normally only special char-languagues may suffer it but solved easily

    Line 289, function makeNode:
    $nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent);

    Items titles doesnt have CDATA so it always pass the htmlentities function.
    Well, then the titles always shows the &code; char system, but in xml, specially in rss, i think that is better to use the numer char system, for example í for í, #243; for ó (there are some functions to made this in htmlentities php.net manual
    I think that the CDATA encodings must be always utf8 char type (with the encoding of document to utf8).
    For fix that, you must replace there the htmlentities of l 289 function by the one that you use for convert to xml char types.

    Sorry for my bad english. Bye.

  17. First off, LOVE THE SCRIPT. Nice simple and works great for most all applications I would need it for, so an big THANK YOU!

    I am having an issue though, I am trying to use this for an Itunes podcast. Here is the issue I am having. I tried just adding xmlns:itunes=”http://www.itunes.com/dtds/podcast-1.0.dtd” to the RSS2 feed and keep my type as RSS2. I also tried going through and creating a new ITUNES class copying the RSS2 class and adding xmlns:itunes=”http://www.itunes.com/dtds/podcast-1.0.dtd” but then removing it from the RSS2 class. When I do that (either option) it inserts the closing tags but without the backslash so technically they are all opening tags.

    Any suggestions?

  18. Hello,
    Great class! I am using it with SimplePie to merge some feeds. Is it possible to add more than one category to an item? Actually only one is added, even if I use a “foreach” loop…

    Thank you for the answer!

  19. Are there any instructions on how to use this RSS Generator? Every time I try it I get a blank page. When I run the Feed Validator I get the following:
    Sorry
    This feed does not validate.

    line 1, column 0: XML parsing error: :1:0: no element found [help]

    In addition, interoperability with the widest range of feed readers could be improved by implementing the following recommendation.

    Feeds should not be served with the “text/html” media type [help]

    Source: http://beta.kavon.com/KAVONNewsCenter/RSS/FeedWriter/example_rss2.php

    Any help would be greatly appreciated.

    Thanks,
    John Novak

  20. One of the problems I got was the following:
    Use of undefined constant DATE_RSS – assumed ‘DATE_RSS’

    I am also getting 3 blank lines at the beginning of the xml code which is causing an error.

    Any ideas?

    Thanks,
    John Novak

  21. im just a beginner in this….but just wanna say i found this feed generator @ the web. Ist also easy to use and cool stuff if ure not into this. Just copy the rss link into the creator and choose your design…

  22. nice, but 2 small things i noticed fast…

    1. pls return your code as a string. so we can echo it ourselves or easily write it to a file. now everything is echoed by the functions
    2. i think you meant to use the name of the function “generateFeed” not “genarateFeed” for the FeedWriter object

  23. Hi
    Who of you are having problem with Non ASCII characters, can try this suggestion from ‘Nacho’.

    See the line 289:
    $nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent);

    Here the htmlentities function is being used with default options. You can see the php manual for list of charsets that are supported by htmlentities and can use your one.

  24. Question here… I’m using your class in a project of mine and all’s working perfectly. Feeds are delivered from domain.com/feed/…

    Now my question is, how do I detect (using PHP) which kind of feed is being requested – Atom, RSS or RSS2 ? As of now, I’m manually setting RSS2 while instantiating FeedWriter.

    Googled for it but couldn’t come up with anything concrete.

    Thanks,
    m^e

  25. Thanks for this code. There’s a lot of typos in it:
    $desciption for $description
    genarate for generate
    Univarsel for Universal

    It makes the code hard to read and search.

  26. I’m not sure how other people were able to get this to work straight out of the box. The copy I downloaded from this site has a flaw that means none of the elements closed properly. To fix it change line 301 of FeedWriter.php to:
    $nodeText .= (in_array($tagName, $this->CDATAEncoding))? “]]>” : “”;

    The original code is missing the slashes:
    $nodeText .= (in_array($tagName, $this->CDATAEncoding))? “]]>” : “”;

    Hope that might save someone some time.

  27. Sorry, that should read:
    $nodeText .= (in_array($tagName, $this->CDATAEncoding))? “]]></$tagName>” : “</$tagName>”;

  28. If anyone is still looking to add the feed validator’s atom:link suggestion: change the genarateFeed function in FeedWriter.php as follows:

    /**
    * Genarate the actual RSS/ATOM file
    *
    * @access public
    * @return void
    */
    public function generateFeed()
    {
    header(“Content-type: text/xml” . ‘; charset=utf-8’);

    $this->printHead();
    $this->printChannels();
    echo ‘channels[‘link’] . ‘” rel=”self” type=”application/rss+xml” />’;
    $this->printItems();
    $this->printTale();
    }

    I also corrected the function name type and added charset=”utf8″. This is just a quick fix if you only generate RRS2 feeds. Some refactoring is in order for a real fix of course.

  29. Hi, I’m using the RSS 2.0 and it seems tobe working alright, but for some reason it doesnt appear right on IE 7. IE just displays XML rather than in HTML format. Has any of you came across this problem too?

  30. 1.
    You use htmlentities() to encode text that goes into non CDATA fields; this produces illegal (undeclared) XML entities.
    You should only encode ‘ ” &

    2.
    You declare encoding=”UTF-8″ in the XML header, but this is entirely platfor dependant. You should add utf8_encode() to be sure that the encoding corresponds to the content, else accented characters will produce errors.

    …and if you could correct all the spelling mistakes… 😉

    But this is still a nice library – thanks!

  31. I tried for over an hour but couldn’t get this script to work. Bugs in FeedWriter.php and elsewhere. Looks great but doesn’t seem to work 🙁

    Is this script out of date?

  32. Hi I’m new to this kind of thing so please bear with me. How do I incorporate this into my site? Do I just follow the way you encoded the information in the examples? Please help.

  33. I use atom feed but i have problem with the Greek characters, i m trying to load it from my database and it give me back the letters as Special characters(like: &beta) on “View page Source” but that happen only to , on the is everything ok. I have tried to chance the live 298 with this code: htmlentities($tagContent, ENT_QUOTES, ‘UTF-8’); and i don’t know why but somehow it strip the slashes from the tags. Anybody know how can i fix that?

    Thanks in advance.

  34. Pingback: barbara digiacomo
  35. Will this class also take care of cleaning the data. Like if you have for instance data that holds html or even worse xml in it will it make sure it won’t break the rss feed produced?

  36. I use you class to make my rss.
    When I tried to validate with feedvalidator says:

    “item should contain a guid element”

    How I can solve this issue?

    Another question:
    I’m using utf-8 at my server and my language is spanish. When I put any character with accent the feed don’t work.

    Have you any solution?

    Thanks in advance.

  37. Hi There,

    Thank you for the class, works really great (after a couple of minutes of tweaking and setting up)…

    Just one thing I would like to confirm. Your closing tags for the items, none of the close with or etc… Is this suppose to be like this? I was unable to get the feed to work until I modified the FeedWriter.php file on line 304 : $nodeText .= (in_array($tagName, $this->CDATAEncoding))? “]]>” : “”;

    It works perfectly now.

  38. Ok, your blog strips out code so my previous comment will make absolutely no sense at all. Basically would like to know why your closing tags on line 304 of the FeedWriter class do not start with a backslast ? I only got it to work after changing your class 🙁 But thanks again for an excellent class!

  39. for displaying non-english characters in item title, don’t forget to change line 42 to:

    $this->CDATAEncoding = array(‘title’, ‘description’, ‘content:encoded’, ‘summary’);

  40. Your a lifesaver!

    This will make it easier for me to update my feeds 🙂
    Combining your script with Feedburner updates my Facebook & Twitter profile on the fly.

  41. Thank you so much for making this AND documenting it well.
    I used it for a unique situation where I had to pull XML from weather.gov into a PHP XML parser, create an RSS, and post it to an .aspx website.

  42. Looks good; thanks for sharing it Have you thought about publishing your code on github (or someplace similar)? It is quite nice for collaboration, and allows you to easily evaluate and merge suggested fixes / improvements.

Leave a Comment

Your email address will not be published. Required fields are marked *