Apache Zeta Components - high quality PHP components

eZ Components - Feed

Introduction

Description

The purpose of the Feed component is to handle parsing and creating RSS and ATOM feeds.

XML feeds overview

XML feeds

An XML feed is an XML document with a certain structure, which lists a series of entries or items.

An example XML feed:

<?xml version="1.0"?> <rss version="2.0"> <channel> <title>Liftoff News</title> <link>http://liftoff.msfc.nasa.gov/</link> <description>Liftoff to Space Exploration.</description> <language>en-us</language> <pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate> <webMaster>webmaster@example.com</webMaster> <item> <title>The Engine That Does More</title> <link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link> <description>Before man travels to Mars, NASA hopes to design new engines that will let us fly through the Solar System more quickly. The proposed VASIMR engine would do that.</description> <pubDate>Tue, 27 May 2003 08:37:32 GMT</pubDate> <guid>http://liftoff.msfc.nasa.gov/2003/05/27.html#item571</guid> </item> <item> <title>Astronauts' Dirty Laundry</title> <link>http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp</link> <description>Compared to earlier spacecraft, the International Space Station has many luxuries, but laundry facilities are not one of them. Instead, astronauts have other options.</description> <pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate> <guid>http://liftoff.msfc.nasa.gov/2003/05/20.html#item570</guid> </item> </channel> </rss>

This XML document describes an RSS2 feed, with channel elements title, link, description, language, pubDate and webMaster. The XML document also contains 2 entries (item), each one with the elements title, link, description, pubDate and guid. These elements are not the only ones present in RSS2 feeds, and some elements are not required to be present.

The Feed document allows creating and parsing such XML documents. The feed types supported by the Feed component are ATOM, RSS1 and RSS2.

Modules

XML feeds are extensible through modules. A module has a namespace and certain XML elements. An example of a feed module is iTunes, which allows creating and parsing podcasts for the iTunes media player.

Example of feed (podcast) with the iTunes module:

<?xml version="1.0" encoding="UTF-8"?> <rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0"> <channel> <title>All About Everything</title> <link>http://www.example.com/podcasts/everything/index.html</link> <description>All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our Podcast in the iTunes Music Store</description> <itunes:subtitle>A show about everything</itunes:subtitle> <itunes:author>John Doe</itunes:author> <itunes:summary>All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our Podcast in the iTunes Music Store</itunes:summary> <itunes:image href="http://example.com/podcasts/everything/AllAboutEverything.jpg" /> <itunes:category text="Technology"> <itunes:category text="Gadgets"/> </itunes:category> <itunes:category text="TV &amp; Film"/> <item> <title>Shake Shake Shake Your Spices</title> <enclosure url="http://example.com/podcasts/everything/AllAboutEverythingEpisode3.m4a" length="8727310" type="audio/x-m4a" /> <guid>http://example.com/podcasts/archive/aae20050615.m4a</guid> <pubDate>Wed, 15 Jun 2005 19:00:00 GMT</pubDate> <itunes:author>John Doe</itunes:author> <itunes:subtitle>A short primer on table spices</itunes:subtitle> <itunes:summary>This week we talk about salt and pepper shakers, comparing and contrasting pour rates, construction materials, and overall aesthetics. Come and join the party!</itunes:summary> <itunes:duration>7:04</itunes:duration> <itunes:keywords>salt, pepper, shaker, exciting</itunes:keywords> </item> <item> <title>Red, Whine, &amp; Blue</title> <enclosure url="http://example.com/podcasts/everything/AllAboutEverythingEpisode1.mp3" length="4989537" type="audio/mpeg" /> <guid>http://example.com/podcasts/archive/aae20050601.mp3</guid> <pubDate>Wed, 1 Jun 2005 19:00:00 GMT</pubDate> <itunes:author>Various</itunes:author> <itunes:subtitle>Red + Blue != Purple</itunes:subtitle> <itunes:summary>This week we talk about surviving in a Red state if you are a Blue person. Or vice versa.</itunes:summary> <itunes:duration>3:59</itunes:duration> <itunes:keywords>politics, red, blue, state</itunes:keywords> </item> </channel> </rss>

The elements of the iTunes module are the ones with itunes: in the element name. They describe the feed (subtitle, author, summary, image, category) and the items (called episodes) in the feed (author, subtitle, summary, duration, keywords). These iTunes elements are not the only ones present in iTunes podcasts.

Applications

XML feeds can be used in many applications:

Class overview

An overview of the most important classes in the Feed component.

Base classes

ezcFeed
Defines a feed object of a specified type. Can be created from scratch or from an existing XML document (with autodetection of type). It can be generated into an XML document.
ezcFeedElement
Base class for all feed element types.
ezcFeedModule
Base class for all feed modules.

Supported feed types

A feed has a type (eg. RSS1, RSS2 or ATOM). The feed type defines which processor is used to parse and generate that type. The following feed processors are supported by the Feed component:

A new processor can be defined by creating a class which extends the class ezcFeedProcessor and implements the interface ezcFeedParser. The new class needs to be added to the supported feed types list by calling the ezcFeed::registerFeed() function.

Supported feed modules

The following modules are supported by the Feed component:

A new module can be defined by creating a class which extends the class ezcFeedModule. The new class needs to be added to the supported modules list by calling the ezcFeed::registerModule() function.

Feed element types

The following element types are implemented in the Feed component (extending the class ezcFeedElement):

Assigning values to feed elements should be done in a way that will not break the resulting XML document. In other words, encoding of special characters to HTML entities is not done by default, and the developer is responsible with calling htmlentities() himself when assigning values to feed elements. Example: if the feed title contains the & character, it is the responsability of the developer to encode it properly as &amp;.

How to create a feed

This part of the tutorial will show you step by step how to create an RSS2 feed which handles the news on a website. Creating an ATOM or RSS1 is similar, although some code needs to be changed. See the Feed creator example for a sample application which can be used to create simple XML feeds of any type (ATOM, RSS1 or RSS2) by providing a simple text file as input.

The information which we want to show in the feed is:

A news item can be defined by these elements (example for one news item):

Step 1. Create a feed object

A feed object can be created by calling the constructor with the optional feed type (atom, rss1 or rss2). In our case we create an generic feed:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. $feed = new ezcFeed();
  5. ?>

The type of the resulting XML feed document will be specified in Step 5. Generate the XML feed.

Step 2. Add feed elements

We add the title, description and author to the feed:

  1. <?php
  2. $feed->title 'eZ news feed';
  3. $feed->description 'This RSS feed contains news feeds for eZ Publish and eZ Components';
  4. $feed->published 'Wed, 05 Mar 2008 14:28:45 +0000';
  5. ?>

Because some feed types support multiple link and author elements, multiple elements of this type can be added to a feed (although this is not fully supported by RSS2 Specifications or by aggregator programs).

The way to add an element which can appear multiple times, or an element which supports attributes, is to call the method add() from ezcFeed or ezcFeedElement classes. The attributes of the element are set as simple properties (the way $feed->title is set).

So to add a author element to our feed, we will do:

  1. <?php
  2. $author $feed->add'author' );
  3. $author->name 'Derick';
  4. $author->email 'nospam@ez.no';
  5. ?>

In the above example. $author is an object of type ezcFeedPersonElement. Other properties can be set on it (uri) which are mainly used for ATOM feeds. When generating an RSS2 feed, the generated XML element will look like this (from the values added to the $author object above):

<managingEditor>nospam@ez.no (Derick)</managingEditor>

In ATOM it will look like this:

<author> <name>Derick</name> <email>nospam@ez.no</email> </author>

To add a link element to our feed, we will do:

  1. <?php
  2. $link $feed->add'link' );
  3. $link->href 'http://ez.no/';
  4. ?>

In the above example. $link is an object of type ezcFeedLinkElement. Other properties can be set on it (title, rel, hreflang, type, length) which are mainly used for ATOM feeds.

Step 3. Add an item

A feed item is an element which can appear multiple times, so it is added via the method add() of ezcFeed:

  1. <?php
  2. $item $feed->add'item' );
  3. ?>

Next we add the title, description and author elements to the news item:

  1. <?php
  2. $item->title 'eZ Components 2007.1 released';
  3. $item->description 'The new release of eZ Components include Workflow, Authentication...';
  4. $item->published 'Mon, 02 Jul 2007 11:36:45 +0000';
  5. ?>

We add the link and author elements to the news item in the same way as for the feed:

  1. <?php
  2. $author $item->add'author' );
  3. $author->name 'Derick';
  4. $author->email 'nospam@ez.no';
  5. $link $item->add'link' );
  6. $link->href 'http://ezcomponents.org/resources/news/news-2007-07-02';
  7. ?>

Step 4. Add more items

To add more news items to our feed, we repeat the step 3 as many times as needed.

Step 5. Generate the XML feed

To create the XML feed from the $feed object, we call the generate() method of ezcFeed:

  1. <?php
  2. $xml $feed->generate'rss2' );
  3. ?>

After running this line, $xml will contain the XML string of the feed (in case no exceptions were thrown due to required elements not being present).

This is the string from $xml with 3 news items:

<?xml version="1.0" encoding="utf-8"?> <rss version="2.0"> <channel> <title>eZ news feed</title> <link>http://ez.no/</link> <description>This RSS feed contains news feeds for eZ Publish and eZ Components.</description> <managingEditor>nospam@ez.no (Derick)</managingEditor> <pubDate>Wed, 05 Mar 2008 14:28:45 +0000</pubDate> <lastBuildDate>Thu, 22 May 2008 08:45:26 +0000</lastBuildDate> <generator>eZ Components Feed dev (http://ezcomponents.org/docs/tutorials/Feed)</generator> <docs>http://www.rssboard.org/rss-specification</docs> <item> <title>eZ Components 2007.1 released</title> <link>http://ezcomponents.org/resources/news/news-2007-07-02</link> <description>The new release of eZ Components include Workflow, Authentication...</description> <author>nospam@ez.no (Derick)</author> <guid isPermaLink="true">http://ezcomponents.org/resources/news/news-2007-07-02</guid> <pubDate>Mon, 02 Jul 2007 11:36:45 +0000</pubDate> </item> <item> <title>eZ Publish 4.0 released</title> <link>http://ez.no/company/news/first_stable_ez_publish_4_0_release_for_php_5</link> <description>The new release of eZ Publish is based on PHP 5....</description> <author>nospam@ez.no (Ole)</author> <guid isPermaLink="true">http://ez.no/company/news/first_stable_ez_publish_4_0_release_for_php_5</guid> <pubDate>Tue, 03 Jul 2007 16:59:00 +0000</pubDate> </item> <item> <title>eZ Find 1.0 released</title> <link>http://ez.no/ezfind/news/ez_find_1_0_2_for_ez_publish_3_10_and_ez_find_1_0_0beta2_for_ez_publish_4_0_released</link> <description>A new product in the eZ family of open-source solutions...</description> <author>nospam@ez.no (Kåre)</author> <guid isPermaLink="true">http://ez.no/ezfind/news/ez_find_1_0_2_for_ez_publish_3_10_and_ez_find_1_0_0beta2_for_ez_publish_4_0_released</guid> <pubDate>Wed, 04 Jul 2007 14:35:00 +0000</pubDate> </item> </channel> </rss>

Some elements were added automatically, namely lastBuildDate (current system time at generation time), generator (eZ Components Feed along with the version of the Feed component (dev) and a link to this tutorial) and docs (http://www.rssboard.org/rss-specification - a link to the RSS2 Specifications).

If you want to generate ATOM and RSS1 feed documents at this step, you can call generate() with atom and rss1 respectively as arguments. As some elements are required for ATOM and RSS1, you might receive an exception. In this case add the required elements and call generate() again.

Step 6. Save the XML feed to a file

The generated XML feed needs to be saved in a file in order to be made accessible to users of your website:

  1. <?php
  2. file_put_contents'feeds/news.xml'$xml );
  3. ?>

Assuming that our host is ez.no, this will be the location of our newly created XML feed: http://ez.no/feeds/news.xml.

You can also output the XML directly, while setting the HTTP Content-Type header:

  1. <?php
  2. $xml $feed->generate'rss2' );
  3. header'Content-Type: ' $feed->getContentType() . '; charset=utf-8' );
  4. echo $xml;
  5. ?>

Assuming that this script is kept in http://ez.no/feeds/news.php, when opening this URL in a web browser, the XML will be output with the content-type application/rss+xml. If the browser is configured properly to handle this content-type, it will open the feed aggregator software program, otherwise it will ask the user which application to use for that content-type.

Step 7. Feed validation

Use a feed validator to validate your newly created feed. Some warnings can appear, but unless the feed is not validated, it should be parseable by most applications and aggregator programs.

Step 8. Make the XML feed accessible

There are some methods to let the user know that a website provides an XML feed, so that the user can save the feed link in his feed aggregator.

Automatic feed discovery

In the HTML source of every page add this line for RSS1 or RSS2 feeds:

<link rel="alternate" type="application/rss+xml" href="http://ez.no/feeds/news.xml" title="eZ news feed" />

Or this line for ATOM feeds:

<link rel="alternate" type="application/atom+xml" href="http://ez.no/feeds/news.xml" title="eZ news feed" />

In modern browsers the user will be informed (usually via a small icon like feed icon in one corner of the browser or in the address bar) that the current page has a web feed. If the user clicks on this icon his feed aggregator client will start and save the link to the feed in its database (if the user's system has a feed aggregator client and is configured to handle application/rss+xml and application/atom+xml content with the aggregator).

Multiple feeds can be added to the same page (for example you can provide ATOM and RSS2 feeds). Note: some browsers might not recognize the non-standard application/rss+xml type and select the ATOM feed by default.

The title attribute of the link HTML tag can be used to differentiate between multiple feeds (for example News, Latest offers, etc).

Link to the feed document

In the HTML source of every page (usually in the header and/or footer) add this line for RSS1 or RSS2 feeds:

<a type="application/rss+xml" href="http://ez.no/feeds/news.xml" title="eZ news feed">RSS feed</a>

Or this line for ATOM feeds:

<a type="application/atom+xml" href="http://ez.no/feeds/news.xml" title="eZ news feed">ATOM feed</a>

The user can drag this link to his feed aggregator, where it will be added to the aggregator's database of feeds.

It is customary to add the feed icon feed icon next to a feed link, so that the user finds the feed link easier on the page. See this Mozilla page for more information about the feed icon.

Feed creator example

In the sub-directory Feed/docs/examples there is a feed_creator application which can be used to create simple XML feeds from minimal text files.

The structure of the text files accepted by this application is:

Feed title Feed link Feed published date Feed author name Feed author email Feed description Item 1 title Item 1 link Item 1 published date Item 1 author name Item 1 author email Item 1 description Item 2 title Item 2 link Item 2 published date Item 2 author name Item 2 author email Item 2 description .. etc

An example of an input text file:

eZ news feed http://ez.no/ Wed, 05 Mar 2008 14:28:45 +0000 Derick nospam@ez.no This RSS feed contains news feeds for eZ Publish and eZ Components. eZ Components 2007.1 released http://ezcomponents.org/resources/news/news-2007-07-02 Mon, 02 Jul 2007 11:36:45 +0000 Derick nospam@ez.no The new release of eZ Components include Workflow, Authentication... eZ Publish 4.0 released http://ez.no/company/news/first_stable_ez_publish_4_0_release_for_php_5 Tue, 03 Jul 2007 16:59:00 +0000 Ole nospam@ez.no The new release of eZ Publish is based on PHP 5.... eZ Find 1.0 released http://ez.no/ezfind/news/ez_find_1_0_2_for_ez_publish_3_10_and_ez_find_1_0_0beta2_for_ez_publish_4_0_released Wed, 04 Jul 2007 14:35:00 +0000 Kåre nospam@ez.no A new product in the eZ family of open-source solutions...

The feed_creator application will read an input file with the above structure and output an XML feed of the chosen type (rss1, rss2 or atom). An XML file will also be written in the same directory as the input file, with the name of the input file plus the .xml extension.

Special characters need to be encoded already in the input text file (eg. if the title contains &, it should appear as &amp; in the input text file).

Example of usage (current directory is the feed_creator directory):

php feed_creator.php rss2 data/news.txt

After running this command, the file data/news.xml will be created, containing an RSS2 feed with the values read from data/news.txt:

<?xml version="1.0" encoding="utf-8"?> <rss version="2.0"> <channel> <title>eZ news feed</title> <link>http://ez.no/</link> <description>This RSS feed contains news feeds for eZ Publish and eZ Components.</description> <managingEditor>nospam@ez.no (Derick)</managingEditor> <pubDate>Wed, 05 Mar 2008 14:28:45 +0000</pubDate> <lastBuildDate>Thu, 22 May 2008 08:45:26 +0000</lastBuildDate> <generator>eZ Components Feed dev (http://ezcomponents.org/docs/tutorials/Feed)</generator> <docs>http://www.rssboard.org/rss-specification</docs> <item> <title>eZ Components 2007.1 released</title> <link>http://ezcomponents.org/resources/news/news-2007-07-02</link> <description>The new release of eZ Components include Workflow, Authentication...</description> <author>nospam@ez.no (Derick)</author> <guid isPermaLink="true">http://ezcomponents.org/resources/news/news-2007-07-02</guid> <pubDate>Mon, 02 Jul 2007 11:36:45 +0000</pubDate> </item> <item> <title>eZ Publish 4.0 released</title> <link>http://ez.no/company/news/first_stable_ez_publish_4_0_release_for_php_5</link> <description>The new release of eZ Publish is based on PHP 5....</description> <author>nospam@ez.no (Ole)</author> <guid isPermaLink="true">http://ez.no/company/news/first_stable_ez_publish_4_0_release_for_php_5</guid> <pubDate>Tue, 03 Jul 2007 16:59:00 +0000</pubDate> </item> <item> <title>eZ Find 1.0 released</title> <link>http://ez.no/ezfind/news/ez_find_1_0_2_for_ez_publish_3_10_and_ez_find_1_0_0beta2_for_ez_publish_4_0_released</link> <description>A new product in the eZ family of open-source solutions...</description> <author>nospam@ez.no (Kåre)</author> <guid isPermaLink="true">http://ez.no/ezfind/news/ez_find_1_0_2_for_ez_publish_3_10_and_ez_find_1_0_0beta2_for_ez_publish_4_0_released</guid> <pubDate>Wed, 04 Jul 2007 14:35:00 +0000</pubDate> </item> </channel> </rss>

See the section Step 8. Make the XML feed accessible for details on how to provide access to the generated XML feed.

How to create an iTunes podcast

A podcast is a collection of media files (called episodes) distributed over the Internet using XML feeds. The podcast doesn't contain the media file, but it contains links to these media files, plus information about the files (meta-information) like creator, duration, category, copyright information, etc.

The Feed component supports creating and parsing feeds which define podcasts.

This part of the tutorial will show you step by step how to create an RSS2 podcast with iTunes elements. The iTunes media player supports RSS2 feeds, so creating ATOM or RSS1 podcasts for iTunes is not recommended (although possible).

The information which we want to show in the podcast is:

iTunes elements for the whole feed:

An episode can be defined by these elements (example for one episode):

In addition, these iTunes elements are added for each episode:

See the section How to create a feed for detailed steps. This part of the tutorial will concentrate on how to add the iTunes information to the feed.

Step 1. Create an RSS2 feed

We start with creating an RSS2 feed object, which we fill with title, description, author and link elements:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. $feed = new ezcFeed'rss2' );
  5. $feed->title 'Flight of the RC plane';
  6. $feed->description 'A podcast for fans of remote-control planes, with information about planes, competitions, tutorials and tips';
  7. $author $feed->add'author' );
  8. $author->name 'Derick';
  9. $author->email 'editor@rcplanes.example.com';
  10. $link $feed->add'link' );
  11. $link->href 'http://rcplanes.examples.com/';
  12. ?>

Step 2. Add iTunes feed elements

The iTunes elements will be contained in an iTunes module. A module is added to an ezcFeed or ezcFeedItem object using the method addModule(). A module is an object of class ezcFeedModule.

Next we will add category, keywords, image, subtitle and explicit iTunes elements to our $feed object:

  1. <?php
  2. $iTunes $feed->addModule'iTunes' );
  3. $iTunes->keywords 'RC planes,gadgets,flying';
  4. $iTunes->explicit 'yes';
  5. $iTunes->subtitle 'Competitions, tutorials and tips for remote-control planes';
  6. // add an image for the podcast
  7. $image $iTunes->add'image' );
  8. $image->link 'http://rcplanes.example.com/images/rc_plane_big.jpg';
  9. // add the podcast in the category Technology->Gadgets
  10. $category $iTunes->add'category' );
  11. $category->term 'Technology';
  12. $subCategory $category->add'category' );
  13. $subCategory->term 'Gadgets';
  14. ?>

See the iTunes categories page for a list of the iTunes categories you can add a podcast to. Note: some category names contain & which should be encoded as &amp; (eg. Society &amp; Culture).

Step 3. Add an item

Next we will add an episode (item) to our $feed object, and we will add the title, description, author and link elements to it:

  1. <?php
  2. $item $feed->add'item' );
  3. $item->title 'Flying an RC plane indoors';
  4. $item->description 'In this episode, Derick talks about how to fly an RC plane in a big hall, around people working and throwing stuff at the plane';
  5. $item->published 'Fri, 04 Jan 2008 11:18:34 +0100';
  6. $author $item->add'author' );
  7. $author->name 'Derick';
  8. $author->email 'derick@rcplanes.example.com';
  9. $link $item->add'link' );
  10. $link->href 'http://rcplanes.example.com/articles/fly-an-rc-plane-indoors.html';
  11. $enclosure $item->add'enclosure' );
  12. $enclosure->url 'http://rcplanes.example.com/media/003-flying-indoors.mp3';
  13. $enclosure->length 49099054// bytes
  14. $enclosure->type 'audio/x-mp3';
  15. ?>

Step 4. Add iTunes item elements

We will add the iTunes elements duration and keywords to our $item object from the previous step:

  1. <?php
  2. $iTunes $item->addModule'iTunes' );
  3. $iTunes->duration '29:20';
  4. $iTunes->keywords 'RC planes,office,flying,enemies';
  5. ?>

Step 5. Add more items

To add more episodes to our podcast, we repeat the steps 3 and 4 as many times as needed.

Step 6. Generate the XML feed

Follow these steps from the previous tutorial How to create a feed:

In the end, our podcast will look like this (with 3 episodes added):

<?xml version="1.0" encoding="utf-8"?> <rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"> <channel> <title>Flight of the RC plane</title> <link>http://rcplanes.examples.com/</link> <description>A podcast for fans of remote-control planes, with information about planes, competitions, tutorials and tips</description> <managingEditor>editor@rcplanes.example.com (Derick)</managingEditor> <pubDate>Thu, 24 Apr 2008 08:55:49 +0000</pubDate> <generator>eZ Components Feed dev (http://ezcomponents.org/docs/tutorials/Feed)</generator> <docs>http://www.rssboard.org/rss-specification</docs> <itunes:category text="Technology"> <itunes:category text="Gadgets"/> </itunes:category> <itunes:explicit>yes</itunes:explicit> <itunes:image href="http://rcplanes.example.com/images/rc_plane_big.jpg"/> <itunes:keywords>RC planes,gadgets,flying</itunes:keywords> <itunes:subtitle>Competitions, tutorials and tips for remote-control planes</itunes:subtitle> <item> <title>Flying an RC plane indoors</title> <link>http://rcplanes.example.com/articles/fly-an-rc-plane-indoors.html</link> <description>In this episode, Derick talks about how to fly an RC plane in a big hall, around people working and throwing stuff at the plane</description> <author>derick@rcplanes.example.com (Derick)</author> <enclosure url="http://rcplanes.example.com/media/003-flying-indoors.mp3" length="49099054" type="audio/x-mp3"/> <pubDate>Fri, 04 Jan 2008 11:18:34 +0100</pubDate> <itunes:duration>29:20</itunes:duration> <itunes:keywords>RC planes,office,flying,enemies</itunes:keywords> </item> <item> <title>The mutant RC flying insect from Hell</title> <link>http://rcplanes.example.com/articles/mutant-rc-flying-insect.html</link> <description>Gunny just got back from a 2-months vacation in Tokyo with the ultimate RC toy ever (TM) - a mean and noisy RC flying insect based on top-secret Japanese technology</description> <author>gunny@rcplanes.example.com (Gunny)</author> <enclosure url="http://rcplanes.example.com/media/004-mutant-rc-flying-insect.mp3" length="74039198" type="audio/x-mp3"/> <pubDate>Tue, 22 Jan 2008 16:58:00 +0100</pubDate> <itunes:duration>44:37</itunes:duration> <itunes:keywords>RC planes,office,flying,insect,Japanese</itunes:keywords> </item> <item> <title>The catcher in the potato field</title> <link>http://rcplanes.example.com/articles/potato-field.html</link> <description>Five RC planes fight to the death for the total control of the potato field - who will win?</description> <author>derick@rcplanes.example.com (Derick)</author> <enclosure url="http://rcplanes.example.com/media/005-potato-field.mp3" length="95039198" type="audio/x-mp3"/> <pubDate>Tue, 22 Apr 2008 18:30:00 +0100</pubDate> <itunes:duration>58:20</itunes:duration> <itunes:keywords>RC planes,potato,field,flying,fight</itunes:keywords> </item> </channel> </rss>

Step 7. Submit the podcast to the iTunes Store

Follow the steps on the section Submitting Your Podcast to the iTunes Store from the iTunes Specifications.

The iTunes Specifications contains other useful information you might need when you are creating podcasts.

How to parse an XML feed

An XML feed can be stored in a file, at an URL or in a string variable. By using the methods parse() (for files and URLs) or parseContent() (for string variables), an ezcFeed object can be created from an XML feed.

This part of the tutorial will show you step by step how to parse an XML feed, read its elements, iterate over the items in the feed and read the items' elements.

Step 1. Parse an XML feed

If the XML feed is stored in a file or URL, use the static method parse() from ezcFeed to parse the feed and create an ezcFeed object out of it:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. $feed ezcFeed::parse'http://ezcomponents.org/feed/news.xml' ); // URL
  5. $feed ezcFeed::parse'/tmp/news.xml' ); // local file
  6. ?>

If the XML feed is protected with HTTP authentication (username and password required in order to access it), provide the username and password in the URL:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. $feed ezcFeed::parse'http://username:password@ezcomponents.org/feed/news.xml' );
  5. ?>

If trying to parse an XML document protected with HTTP authentication without providing a valid username and password, an ezcFeedParseErrorException will be thrown.

If the XML feed is stored in a string variable, use the static method parseContent() from ezcFeed to parse the feed and create an ezcFeed object out of it:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. $feed ezcFeed::parseContent$xml ); // $xml is a string
  5. ?>

These exceptions can be thrown while parsing a feed:

Step 2. Read the feed elements

At step 1 we created an ezcFeed object by parsing an XML feed. Next we will read the elements from the feed.

Depending on the feed type, certain elements are present while others are not. The feed type can be retrieved via the method getFeedType() from ezcFeed:

  1. <?php
  2. $feedType $feed->getFeedType();
  3. ?>

This will return rss1, rss2 or atom.

It is always a good idea to read only those elements which are present in $feed. To test if an element is present, call isset() on it:

  1. <?php
  2. if ( isset( $feed->title ) )
  3. {
  4.     $title $feed->title->__toString();
  5. }
  6. ?>

Another way to write this is (assuming that a missing title can be considered null):

  1. <?php
  2. $title = isset( $feed->title ) ? $feed->title->__toString() : null;
  3. ?>

Depending on your application, you might need only some elements, let's say title, description, author and link. So to read those elements you will use:

  1. <?php
  2. $title = isset( $feed->title ) ? $feed->title->__toString() : null;
  3. $description = isset( $feed->description ) ? $feed->description->__toString() : null;
  4. if ( isset( $feed->author ) )
  5. {
  6.     $author = isset( $feed->author->name ) ? $feed->author->name null;
  7.     // RSS2 feeds usually have the author in this format: email_address (author_name)
  8.     // the $author string can be parsed to extract the email and name.
  9.     //
  10.     // ATOM feeds contain the author's email in a separate element: $feed->author->email.
  11.     // and in addition they have the uri element for authors: $feed->author->uri
  12. }
  13. $links = array();
  14. if ( isset( $feed->link ) )
  15. {
  16.     foreach ( $feed->link as $link )
  17.     {
  18.         $links[] = $link->href;
  19.     }
  20. }
  21. ?>

Because link can appear multiple times, we had to resort to this long code to get the links out of the feed. The $links array will be empty if no links are in the XML feed, or will contain all the links that appear on the feed-level.

Step 3. Iterate over the feed items

A feed can contain zero or more item elements.

Let's say we want to extract the title, description, published, author and link of all items. This is how we will do it:

  1. <?php
  2. $items = array();
  3. foreach ( $feed->item as $item )
  4. {
  5.     $title = isset( $item->title ) ? $item->title->__toString() : null;
  6.     $description = isset( $item->description ) ? $item->description->__toString() : null;
  7.     $published = isset( $item->published ) ? $item->published->date->format'c' ) : null;
  8.     if ( isset( $item->author ) )
  9.     {
  10.         $author = isset( $item->author->name ) ? $item->author->name null;
  11.         // RSS2 feeds usually have the author in this format: email_address (author_name)
  12.         // the $author string can be parsed to extract the email and name
  13.         //
  14.         // ATOM feeds contain the author's email in a separate element: $item->author->email.
  15.         // and in addition they have the uri element for authors: $item->author->uri
  16.     }
  17.     $links = array();
  18.     if ( isset( $item->link ) )
  19.     {
  20.         foreach ( $item->link as $link )
  21.         {
  22.             $links[] = $link->href;
  23.         }
  24.     }
  25.     $items[] = array( 'title' => $title,
  26.                       'description' => $description,
  27.                       'author' => $author,
  28.                       'links' => $links );
  29. }
  30. ?>

The published element is an ezcFeedDateElement object encapsulating a DateTime object, so we return the date as a string with format( 'c' ). Other formats can be used also, see the documentation for date_format().

How to parse an iTunes podcast

See the section How to parse an XML feed for detailed steps. This part of the tutorial will concentrate on how to fetch the iTunes information from an RSS2 feed.

Step 1. Parse an XML feed

If the XML feed is stored in a file or URL, use the static method parse() from ezcFeed to parse the feed and create an ezcFeed object out of it:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. $feed ezcFeed::parse'http://rcplanes.example.com/feed/podcast.xml' );
  5. $feed ezcFeed::parse'/tmp/podcast.xml' ); // local file
  6. ?>

If the XML feed is protected with HTTP authentication (username and password required in order to access it), provide the username and password in the URL:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. $feed ezcFeed::parse'http://username:password@rcplanes.example.com/feed/podcast.xml' );
  5. ?>

If trying to parse an XML document protected with HTTP authentication without providing a valid username and password, an ezcFeedParseErrorException will be thrown.

If the XML feed is stored in a string variable, use the static method parseContent() from ezcFeed to parse the feed and create an ezcFeed object out of it:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. $feed ezcFeed::parseContent$xml ); // $xml is a string
  5. ?>

Step 2. Read the feed elements

Depending on the feed type, certain elements are present while others are not. The feed type can be retrieved via the method getFeedType() from ezcFeed:

  1. <?php
  2. $feedType $feed->getFeedType();
  3. ?>

This will return rss1, rss2 or atom.

Depending on your application, you might need only some elements, let's say title, description, author and link. So to read those elements you will use:

  1. <?php
  2. $title = isset( $feed->title ) ? $feed->title->__toString() : null;
  3. $description = isset( $feed->description ) ? $feed->description->__toString() : null;
  4. if ( isset( $feed->author ) )
  5. {
  6.     $author = isset( $feed->author->name ) ? $feed->author->name null;
  7.     // RSS2 feeds usually have the author in this format: email_address (author_name)
  8.     // the $author string can be parsed to extract the email and name
  9.     //
  10.     // ATOM feeds contain the author's email in a separate element: $feed->author->email.
  11.     // and in addition they have the uri element for authors: $feed->author->uri
  12. }
  13. $links = array();
  14. if ( isset( $feed->link ) )
  15. {
  16.     foreach ( $feed->link as $link )
  17.     {
  18.         $links[] = $link->href;
  19.     }
  20. }
  21. ?>

Step 3. Read the iTunes feed elements

Before reading iTunes elements from the feed, we need to make sure that the feed has the iTunes module. We use the method hasModule() from ezcFeed or ezcFeedItem:

  1. <?php
  2. if ( $feed->hasModule'iTunes' ) )
  3. {
  4.     // process the iTunes module
  5. }
  6. ?>

We can also call the isset() method to check if the iTunes module is present:

  1. <?php
  2. if ( isset( $feed->iTunes ) )
  3. {
  4.     // process the iTunes module
  5. }
  6. ?>

This is how we fetch information from the iTunes module. Let's say we want to fetch the keywords, subtitle, image and category elements:

  1. <?php
  2. if ( isset( $feed->iTunes ) )
  3. {
  4.     $iTunes $feed->iTunes;
  5.     $keywords = isset( $iTunes->keywords ) ? $iTunes->keywords->__toString() : null;
  6.     $subtitle = isset( $iTunes->subtitle ) ? $iTunes->subtitle->__toString() : null;
  7.     $image = isset( $iTunes->image ) ? $iTunes->image->__toString() : null;
  8.     $categories = array();
  9.     if ( isset( $iTunes->category ) )
  10.     {
  11.         foreach ( $iTunes->category as $category )
  12.         {
  13.             $cat = array( 'term' => $category->term );
  14.             if ( isset( $category->category ) )
  15.             {
  16.                 $cat['subCategory'] = $category->category->term;
  17.             }
  18.             $categories[] = $cat;
  19.         }
  20.     }
  21. }
  22. ?>

In iTunes, category is an element which can have sub-categories. The code above reads the category values (from the text attribute) and the sub-category (if any) from each category. The $categories array can look like this:

array( 0 => array( 'term' => 'Technology', 'subCategory' => 'Gadgets' ), );

if the iTunes elements appeared like this in the XML feed:

<category text="Technology"> <category text="Gadgets"/> </category>

Step 4. Iterate over the feed items

Let's say we want to extract the title, description, published, author and link of all items. This is how we will do it:

  1. <?php
  2. $items = array();
  3. foreach ( $feed->item as $item )
  4. {
  5.     $title = isset( $item->title ) ? $item->title->__toString() : null;
  6.     $description = isset( $item->description ) ? $item->description->__toString() : null;
  7.     $published = isset( $item->published ) ? $item->published->date->format'c' ) : null;
  8.     if ( isset( $item->author ) )
  9.     {
  10.         $author = isset( $item->author->name ) ? $item->author->name null;
  11.         // RSS2 feeds usually have the author in this format: email_address (author_name)
  12.         // the $author string can be parsed to extract the email and name
  13.         //
  14.         // ATOM feeds contain the author's email in a separate element: $item->author->email.
  15.         // and in addition they have the uri element for authors: $item->author->uri
  16.     }
  17.     $links = array();
  18.     if ( isset( $item->link ) )
  19.     {
  20.         foreach ( $item->link as $link )
  21.         {
  22.             $links[] = $link->__toString();
  23.         }
  24.     }
  25.     $media = array();
  26.     if ( isset( $item->enclosure ) )
  27.     {
  28.         $enclosure $item->enclosure[0];
  29.         $media = array(
  30.            'url' => isset( $enclosure->url ) ? $enclosure->url null,
  31.            'length' => isset( $enclosure->length ) ? $enclosure->length null,
  32.            'type' => isset( $enclosure->type ) ? $enclosure->type null
  33.            );
  34.     }
  35.     $items[] = array( 'title' => $title,
  36.                       'description' => $description,
  37.                       'author' => $author,
  38.                       'links' => $links,
  39.                       'media' => $media );
  40. }
  41. ?>

After running the code, the $media array will contain the url, length and type of the media file specified in the feed item. The $media array is added to the $items array to be processed later by the application.

Step 5. Read the iTunes item elements

Let's say we want to fetch the duration of the iTunes module inside an item. The code from the previous section is altered as follows:

  1. <?php
  2. // ...
  3.     $media = array();
  4.     if ( isset( $item->enclosure ) )
  5.     {
  6.         $enclosure $item->enclosure[0];
  7.         $media = array(
  8.            'url' => isset( $enclosure->url ) ? $enclosure->url null,
  9.            'length' => isset( $enclosure->length ) ? $enclosure->length null,
  10.            'type' => isset( $enclosure->type ) ? $enclosure->type null
  11.            );
  12.         if ( isset( $item->iTunes ) )
  13.         {
  14.             $iTunes $item->iTunes;
  15.             $media['duration'] = isset( $iTunes->duration ) ? $iTunes->duration null;
  16.         }
  17.     }
  18. // ...
  19. ?>

After running the code, the $media array will contain the url, length and type of the media file specified in the feed item, and the duration of the media file taken from the iTunes module (if available).

Best practices

This section lists some useful tips for handling feed documents.

Universal feed generator

In order to generate all 3 feed types (ATOM, RSS1, RSS2) from the same ezcFeed data, these elements must be added to an ezcFeed object:

And these elements must be added to an ezcFeedEntryElement object:

This is a minimal script to be able to generate all 3 feed types from the same ezcFeed data:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. $feed = new ezcFeed();
  5. $author $feed->add'author' );
  6. $author->name "Indiana Jones";
  7. $author->email "indy@example.com";
  8. $feed->description "This feed shows Indiana Jones movie releases";
  9. $feed->id "http://indy.example.com/";
  10. $link $feed->add'link' );
  11. $link->href "http://indy.example.com/";
  12. $feed->title "Indiana Jones movie releases";
  13. $feed->updated time();
  14. // add a feed item
  15. $item $feed->add'item' );
  16. $author $item->add'author' );
  17. $author->name "Indiana Jones";
  18. $author->email "indy@example.com";
  19. $item->description "Indy meets ****** and has a hell of an adventure";
  20. $item->id "http://indy.example.com/4";
  21. $link $item->add'link' );
  22. $link->href "http://indy.example.com/4";
  23. $item->title "Indiana Jones and the Kingdom of the Crystal Skull";
  24. $item->updated time();
  25. $atom $feed->generate'atom' );
  26. $rss1 $feed->generate'rss1' );
  27. $rss2 $feed->generate'rss2' );
  28. ?>

Self link

A feed validator application will usually recommend that a feed contains a link to itself, in other words the URL of the feed should be included inside the feed.

To add this information to a feed, use the following section.

ATOM

Add a link element with the attribute rel=self (this is required):

$link = $feed->add( 'link' ); $link->href = 'http://example.com/'; $link->rel = 'self';
RSS1

Use the about attribute, accessed as id (this is required):

$feed->id = 'http://example.com/';
RSS2

Most feed validator applications will recommend to include in an RSS2 feed a link to the location of the feed. For example, if the XML document containing the RSS2 feed is located at 'http://example.com/rss/', then this URL should be contained in the feed itself in an atom:link element, since RSS2 does not offer a mechanism to specify self-links.

Use the id element of a feed to add this self-link:

$feed->id = 'http://example.com/';

This will be rendered in XML as:

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> ... <atom:link href="http://example.com/" rel="self" type="application/rss+xml"/>

Media type

ATOM

All ATOM feeds must be identified with the application/atom+xml media type. Use the getContentType() method after calling generate( 'atom' ) on an ezcFeed object to get this string, or use ezcFeedAtom::CONTENT_TYPE.

RSS1

All RSS1 feeds should be identified with the application/rss+xml media type (although it is not a standard yet). Use the getContentType() method after calling generate( 'rss1' ) on an ezcFeed object to get this string, or use ezcFeedRss1::CONTENT_TYPE.

RSS2

All RSS2 feeds should be identified with the application/rss+xml media type (although it is not a standard yet). Use the getContentType() method after calling generate( 'rss2' ) on an ezcFeed object to get this string, or use ezcFeedRss2::CONTENT_TYPE.

Extending the Feed component

Register a new feed type

A new feed type can be defined by creating a class which extends the class ezcFeedProcessor and implements the interface ezcFeedParser. The new class needs to be added to the supported feed types list by calling the ezcFeed::registerFeed() function.

Example of new feed type:

  1. <?php
  2. class myOpmlHandler extends ezcFeedProcessor implements ezcFeedParser
  3. {
  4.     const CONTENT_TYPE 'text/x-opml';
  5.     const FEED_TYPE 'opml';
  6.     public function __constructezcFeed $container )
  7.     {
  8.         $this->feedContainer $container;
  9.         $this->feedType self::FEED_TYPE;
  10.         $this->contentType self::CONTENT_TYPE;
  11.     }
  12.     public function generate()
  13.     {
  14.         // write implementation here
  15.         // should return XML as a string based on the feed elements from
  16.         // $this->feedContainer which are accessed as $this->element_name
  17.         // (example $this->title)
  18.     }
  19.     public static function canParseDOMDocument $xml )
  20.     {
  21.         // write implementation here
  22.         // should return true if this class can parse the $xml DOMDocument received
  23.         // and false otherwise
  24.     }
  25.     public function parseDOMDocument $xml )
  26.     {
  27.         // write implementation here
  28.         $feed = new ezcFeed();
  29.         // parse $xml and fill $feed with properties fetched from $xml
  30.         return $feed;
  31.     }
  32. }
  33. ?>

Example of how to use the feed type above:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. ezcFeed::registerFeed'opml''myOpmlHandler' );
  5. $feed = new ezcFeed();
  6. // fill $feed with OPML properties
  7. $xml $feed->generate'opml' );
  8. ?>

Register a new module

A new module can be defined by creating a class which extends the class ezcFeedModule. The new class needs to be added to the supported modules list by calling the ezcFeed::registerModule() function.

Example of a new module type:

  1. <?php
  2. class mySlashHandler extends ezcFeedModule
  3. {
  4.     public function __construct$level 'feed' )
  5.     {
  6.         parent::__construct$level );
  7.     }
  8.     public function generateDOMDocument $xmlDOMNode $root )
  9.     {
  10.         // write implementation here
  11.         // should fill $root with values from $this
  12.     }
  13.     public function parse$nameDOMElement $node )
  14.     {
  15.         // write implementation here
  16.         // should parse $node and add a new ezcFeedElement to $this with name $name
  17.     }
  18.     public function isElementAllowed$name )
  19.     {
  20.         // return true if the element $name is allowed in this module at level $this->level,
  21.         // and false otherwise
  22.     }
  23.     public function add$name )
  24.     {
  25.         // add the element $name to this module at level $this->level (feed-level or item-level)
  26.     }
  27.     public static function getModuleName()
  28.     {
  29.         return 'Slash';
  30.     }
  31.     public static function getNamespace()
  32.     {
  33.         return 'http://purl.org/rss/1.0/modules/slash/';
  34.     }
  35.     public static function getNamespacePrefix()
  36.     {
  37.         return 'slash';
  38.     }
  39. }
  40. ?>

Example of how to use the module above:

  1. <?php
  2. // use eZ Components autoload mechanism
  3. require_once 'tutorial_autoload.php';
  4. ezcFeed::registerModule'Slash''mySlashHandler''slash');
  5. $feed = new ezcFeed();
  6. $item $feed->add'item' );
  7. $slash $item->addModule'Slash' );
  8. // add properties for the Slash module to $slash
  9. $xml $feed->generate'rss2' ); // or the feed type which is needed
  10. ?>

Specifications and RFCs

For a list of supported RFCs and specifications of the feed types and modules, please see the specifications page.