PHP Feeder
  1. 1. Download & license
  2. 2. Features
    1. 2.1. Samples
      1. 2.1.1. More on the chained form
      2. 2.1.2. More on direct assignment
    2. 2.2. Quick start with Text Feeder
      1. 2.2.1. Channel and entry files
  3. 3. Text Feeder
    1. 3.1. One file per entry mode
      1. 3.1.1. Normalization of properties
    2. 3.2. Automatic attachments
  4. 4. YAML format
    1. 4.1. Differences
    2. 4.2. Syntax
  5. 5. Object properties
    1. 5.1. FeedChannel
    2. 5.2. FeedEntry
    3. 5.3. FeedDescriptor
    4. 5.4. FeedObjWithCommonAttrs
  6. 6. Property format strings
    1. 6.1. FeedText
    2. 6.2. FeedContent
    3. 6.3. FeedLinks
    4. 6.4. FeedImage
    5. 6.5. FeedPerson
    6. 6.6. FeedCategory
    7. 6.7. FeedGenerator
    8. 6.8. FeedTextInput
    9. 6.9. FeedCloud

Feeder is a syndication framework for PHP 5+. It generates RSS 0.92, RSS 2.0 and Atom feeds from single data source. Bundled Text Feeder generates feeds from text files so you don’t have to do any coding at all to get your channel running. And, since it’s part of Feeder, it outputs in all three supported feed formats.

Download & license

All Feeder classes and related data is released under public domain. If you use it I’ll appreciate a backlink to this page; if you have feedback – feel free to drop a comment.

Last Feeder update was on 30 May 2012 – version 1.2.

Download PHP Feeder. See also GitHub repo.

Updated 30 May 2012 (v1.2):

Features

Samples

TextFeeder – feed generator from YAML files:

API – dynamically generating feed using chained calls (see also More on the chained form):

PHP
require_once 'chained.php';

Feed::make()  ->title()->add('text''My Feed')->add('html''My <em>Feed</em>')->up()
              ->
author()->name('Proger_XP')->email('proger.xp@gmail.com')->up()
              ->
description()->add('text''Just another PHP Feed')->up()
              ->
baseurl('http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['REQUEST_URI']).'/')
    ->
entry() ->title()->add('text''My first post')->up()
              ->
updated(strtotime('22 Jan 2011'))
              ->
author()->name('Proger_XP')->email('proger.xp@gmail.com')->up()
              ->
content()->add('text''Thinking about something to write...')
                         ->
add('html''Thinking about <em>something</em> to write&hellip;')
    ->
entry() ->title()->add('text''Another filler')->up()
              ->
updated(strtotime('23 May 2012'))
              ->
author()->name('Proger_XP')->email('proger.xp@gmail.com')->up()
              ->
contributor()->name('Camilo')->url('http://camilomm.deviantart.com')->up()
              ->
content()->add('html''Why? Because he\'s my friend <img src="smile.png" />')
    ->
feed()->atom();

API – dynamically generating feed from arrays:

PHP
$channel = array(
  
'title'           => 'My Feed',
  
'author'          => 'Proger_XP proger.xp@gmail.com http://proger.i-forge.net',
  
'description'     => 'Just another PHP Feed',
  
'category'        => 'http://example.com Category Label here.',
  
// it doesn't matter what follows "category" after a space - we need
  // something so this array key is unique and won't override preceding one:
  
'category 2'      => 'Second Label',
  
// it's only possible to set width, height and image URL using text form:
  
'logo'            => '100x20 http://example.com/logo.png',
);

$entries = array(
  array(
    
'title'         => 'My first post',
    
'updated'       => strtotime('22 Jan 2011'),
    
'author'        => 'Proger_XP proger.xp@gmail.com',
    
'content'       => 'Thinking about something to write...',
  ),
  array(
    
'title'         => 'Another filler',
    
'updated'       => strtotime('23 May 2012'),
    
'content html'  => 'Smile! <img src="smile.png" />',
  ),
);

$feeder = new Feeder;
$feeder->Channel()->SetFromArray($channel);

foreach (
$entries as $i => $entry) {
  
$feeder->Entry($i, new FeedEntry($entry));
}

$output = new AtomFeed;
$output->Output($feeder);

API – dynamically generating feed by setting object properties directly (see also More on direct assignment):

PHP
$proger = new FeedPerson;
$proger->Name('Proger_XP');
$proger->URL('http://proger.i-forge.net');

$feeder = new Feeder;

$feeder->Channel()->Title()->Add('text''My Feed');
$feeder->Channel()->Author(0$proger);
$feeder->Channel()->Description()->Add('text''Just another PHP Feed');

$entry = new FeedEntry;

$entry->Title()->Add('text''My first post');
$entry->Updated(strtotime('22 Jan 2011'));
$entry->Author(0$proger);
$entry->Content()->Add('text''Thinking about something to write...');

$feeder->Entry(0$entry);

$entry = new FeedEntry;

$entry->Title()->Add('text''Another filler');
$entry->Updated(strtotime('23 May 2012'));
$entry->Author(0$proger);
$entry->Content()->Add('html''Why? Because he\'s my friend <img src="smile.png" />');

$feeder->Entry(1$entry);

$output = new Rss092Feed;
$output->Output($feeder);

More on the chained form

Basically, chained form allows you calling all methods found in FeedChannel and other classes. Note that in this form you can use lower case method names even though Feeder in itself uses CamelCase so the following calls are all valid: PHPlinkurl(), PHPlinkURL(), PHPLinkURL().

For example, channel inherits from FeedDescriptor (which is common for channel and entry classes) and has Description property as can be seen here. This property is of FeedText type. When we call channel’s PHPDescription() method we retrieve its FeedText object on which we can call PHPAdd() or any other method it has (check its source code in feeder.php – it’s easy to follow).

PHP
Feed::make()                            // we have FeedChannel
  
->title()                             //   now FeedText
    
->add('text''My Feed')            //   adding a string in plain text form
    
->add('html''My <em>Feed</em>')   //   we still have FeedText, adding another string - in HTML form
    
->up()                              // to return to FeedChannel we call up()
  
->description()                       //   we have FeedText representing channel description
    
->add(...)                          //   adding a string to it just like above

Similarly, FeedChannel has Category (FeedCategory), Icon (FeedImage) and other object properties. Here’s how to change them:

PHP
require_once 'chained.php';

Feed::make()->category('http://example.com Category Label here.')
            ->
category('Second Label')
            ->
icon('100x20 http://example.com/icon.gif')
            ->
logo()->imageurl('http://example.com/logo.png')
                    ->
linkurl('http://example.com/home')
                    ->
title('My Example Resource')
                    ->
description()->add('html''Its <em>description</em>.')->up()
                    ->
width(121)
                    ->
height(83)
    ->
feed()->rss20();

More on direct assignment

The best reference to Feeder object properties and methods is its source code (feeder.php). Basic classes like FeedChannel, FeedEntry and their ancestors FeedDescriptor and FeedObjWithCommonAttrs are listed in this section.

For example, here’s how we can assign a feed two categories, icon and logo images:

PHP
$feeder = new Feeder;

$category = new FeedCategory;
$category->URL('http://example.com');
$category->Term('Category');
$category->Label('Label here.');

$feeder->Channel()->Category(0$category);

$category = new FeedCategory;
$category->Term('Second');
$category->Label('Label');

$feeder->Channel()->Category(1$category);

$icon $feeder->Channel()->Icon();;
$icon->Width(100);
$icon->Height(20);
$icon->ImageURL('http://example.com/icon.gif');

$logo $feeder->Channel()->Logo();
$logo->Width(121);
$logo->Height(83);
$logo->ImageURL('http://example.com/logo.png');
$logo->LinkURL('http://example.com/home');
$logo->Title()->Add('text''My Example Resource');
$logo->Description()->Add('html''Its <em>description</em>.');

$output = new Rss20Feed;
$output->Output($feeder);

Quick start with Text Feeder

TextFeeder lets you generate feeds from YAML text files (example) and serve them (examples: Atom, RSS 0.92, RSS 2.0) without the need to configure anything else. Details are given in the section below.

  1. Choose a location where your feed will be accessible. For example, we will take /home/user/public/myfeed/ that corresponds to http://localhost/myfeed/.
  2. Extract the following files there:
  3. Create channel file – you can use any of the following: feed.yml, feed.txt, channel.yml, channel.txt (detected in this order). Details are explained below.
  4. Create entries – their name must be of form YYYYMMDD Title.yml (or .txt if you have chosen feed.txt or channel.txt). Title may contain spaces or be omitted.
  5. Finally, navigate to the Feeder in your browser using this URL: http://localhost/myfeed/. You can use these query parameters:

Note: TextFeeder automatically attaches files to entries if they have the same base name (without .yml or .txt extension) – you can use this to attach related images, archives or other data to your entries as can be seen in the sample feed.

Channel and entry files

All TextFeeder files use simple text YAML format to define key/value pairs. Such files can contain comments (starting with #), blank lines or multiline values – see format description for details. However, the basic element is just this: key: value.

Key names are case-insensitive.

Sample feed.yml file:

confTitle:          My First Feed
Description: >
  Hello! Nice to see you're reading my feed.
  Remember to visit my site when you've got a minute!
Copyright:      (c) Myself
Copyright HTML: &copy; <strong>My</strong>self
Link:           http://myhome.net
Link related:   text/html http://outside.com Friend's blog
Link self:      http://myhome.net/feed/ This feed
Author:         Myself me@myhome.net http://myhome.net
WebMaster:      Myself me@myhome.net http://myhome.net
Contributor:    Micky http://micky.mo
Language:       en_GB
BaseURL:        http://myhome.net

Note: Description property above was specified using YAML’s folded value. In this mode leading and trailing line spaces are trimmed away, single line breaks are collapsed into spaces and double line breaks become single line break.

Full list of available properties is described below; compiled, channel file can have the following properties: Logo, Icon, WebMaster, Rating, PubDate, SkipHours, SkipDays, Generator, TextInput, TTL, Cloud – plus the following common properties: Title, Description, Copyright, Links, Permalink, Author, Contributor, Category, Updated and Language, BaseURL. When using TextFeeder you can also define Data URL and modRewrite.

Sample 20120507 My first post.yml file:

confAuthor:         Myself me@myhome.net http://myhome.net
CommentsURL:    20120507-my-first-post/comments

Content: >
  So this is my first post... Thinking of
  something to write so nothing here yet.

Content HTML: >
  So this <em>is</em> my first post&hellip; Thinking of
  something to write so nothing here yet.
  <img src="smile.png" alt=":)" />

The above file specifies entry author, commenting URL and content in two representations – plain text and HTML. Feeder will choose the best available and convert provided content into an alternative representation if one is missing.

Full list of available properties is described below; compiled, channel file can have the following properties: Published, CommentsURL, Source, Content – plus the following common properties: Title, Description, Copyright, Links, Permalink, Author, Contributor, Category, Updated and Language, BaseURL.

Entry file name sets additional details:

Text Feeder

TextFeeder class is used to load a channel and fill it with entries based on one or more text files in YAML-style format with .yml extension.

You you can also use .txt extension instead of .yml – in this case the feed directory must not contain any files named *.yml. Also note that you won’t be able to autoattach text content to channel and entries when using .txt.

To define a new feed create feed.yml or channel.yml file (both are aliases). A YAML file may contain more than one «document»; you can specify channel entries inside either the same channel file or using separate .yml (or .txt, see above) files – the latter being more convenient as TextFeeder will automatically detect and attach pictures, entry contain and other resources to them. TextFeeder will look for external files if the channel file contains only one document.

Apart from regular FeedChannel properties two special ones can be defined:

Data URL
Sets absolute URL to the location from where TextFeeder serves its content – attached entry files, channel logo and icon, etc. This also is used to construct an URL to the full entry page in HTML format served by TextFeeder.
modRewrite
Enables usage of Apache mod_rewrite when generating full entry URLs using Data URL; plays no role if all entries use explicit Permalinks.

One file per entry mode

This mode is enabled automatically if channel file (feed.yml or channel.yml) contains just one document.

Each entry file must begin with publication date in format YYYYMMDD, for example: 20120325 We have opened.yml (or .txt) – entry is dated March 25th, 2012 and titled «We have opened». This time determines the sorting of feed entries prior to their loading.

Normalization of properties

When TextFeeder loads FeedChannel’s YAML file it sets the following properties to default values unless they were specified:

updated
Is set to last entry publish or update time or if there were none – to the channel’s file modification time.
Generator
Is set to the TextFeeder version string.
Permalink
Is set to the first specified self Link, if there are any.

Entries have these defaults:

Published
Is set to the time retrieved from entry file name (in YYYYMMDD format): 20120325 We have opened.yml – March 25th, 2012.
Title
– Is set to the title retrieved from entry file name: 20120325 We have opened.yml – «We have opened».
Updated
Is set to match published time. If you want to indicate that an entry has been updated set this property explicitly.
Permalink
If unset is treated as served by TextFeeder using its Data URL setting.

Automatic attachments

TextFeeder will automatically set some missing channel and entry fields based on the files in the feed’s root. List of properties getting attachments (X stands for «feed» if channel was defined in feed.yml or for «channel» if it’s in channel.yml; works for .txt feeds as well):

Logo
The first file named X.(png|gif|jpg|jpeg|ico) is attached as the channel logo image (Atom specification prescribes it to have 2:1 aspect ratio).
Icon
The first file named X icon.(png|gif|jpg|jpeg|ico) is attached as the channel icon image (small logo, Atom specification prescribes it to have 1:1 aspect ratio).
Description
Text channel description is read from X.txt file, if any.
Description HTML
HTML channel description is read from X.htm or an .html file, if any.

TextFeeder will also attach the following files for entries (X stands for entry .yml or .txt file name):

Content
Text content is read from X.txt file.
Content HTML
HTML content is read from X.txt file.
Link enclosure
All other X.* files are attached to the entry as enclosures (like attachments in e-mail messages).

YAML format

Differences

Feeder’s YAML files are similar to regular YAML but differ in the following aspects:

  1. Keys with the same name don’t override previous value but create an array instead;
  2. Only folding (>) and preformatted (|) block formats are supported;
  3. Lists and most other markup isn’t supported since it has no use in Feeder;
  4. Comments are only allowed if they’re prefixed with a whitespace (i.e. not allowed inside values).

Syntax

TextFeeder uses its own YAML loading routine which is independent of PHP YAML extension.

A YAML file consists of key-value pairs separated by colons followed with at least one space. Key names re case-insensitive and may contain spaces.

Each value can be defined in 3 ways:

Here’s a sample YAML file:

confSingle line key:    Hellp, world!

Folded value: >
    A "Hello world" program is a computer program
  that outputs "Hello, world" on a display device.

  From Wikipedia, the free encyclopedia.

Preserved: |
  select inner prior
    from 'Hello, world!' / 2
    where level % 2 == 0

Blank lines were added for better readability but don’t affect the processing in any way. The first key contains simple «Hellp, world!» string (without surrounding spaces); the second value consists of two lines both of which have no leading whitespace; the third value still contains 3 lines where only the leading indentation was removed:

select inner prior
  from 'Hello, world!' / 2
  where level % 2 == 0

YAML document supports comments – they must start with hash symbol (#) optionally preceded by spaces. Note that comments cannot appear inside values:

conf# This is a comment line lasting until the line break.
# Another one.
key:            Regular value
folded:         >
  Even though there are more than one space preceding
  ">" symbol it's still a folding block.
  # This is not a comment...
  ...it's rather a part of it because it has indentation.
# And this is a comment.
key 3:          Just another value.

Each YAML file can have multiple documents (for entries only the first is used (parsing is abandoned after meeting the first ---), for channels their presense control «one file per entry» mode). End of stream marker (...) skips the file remainder. For example:

confTitle:          Our Channel
Title HTML:     <em>Our</em> Channel
---
Published:      9 Nov 2011
Description:    This is the first entry we have.
---
Published:      6 May 2012
Title:          We're back!

The above YAML markup defines 3 documents each having 2 keys. If this is placed in feed.yml TextFeeder will treat the first document as the channel definition and second and third will be definitions of the two entries it has.

In TextFeeder, YAML markup allows multiple keys with the same name – in this case an array is created rather then the later overriding the preceding one:

confAuthor:         Proger_XP proger.xp@gmail.com
Author:         Freeman http://freeman-s.net

Object properties

FeedChannel

FeedChannel inherits from FeedDescriptorFeedObjWithCommonAttrs; its properties:

Logo FeedImageFull-size channel logo picture, Atom specification requires it to have 2:1 aspect ratio.
Icon FeedImageSmall channel icon, Atom specification requires it to have 1:1 aspect ratio.
WebMasters array of FeedPersonWebmasters responsible for this feed or overall site production.
WebMaster FeedPersonShorthand property for setting WebMasters (see above).
Rating stringChannel ratin – e.g. «SFW» which means «Safe For Work».
PubDate timestampThe next time this cahnnel will be updated with new contents.
SkipHours array of integersList of day hours (0-23) when this channel is guaranteed not to be updated with new contents (e.g. at night).
SkipDays array of stringsList of week days («Monday», etc.) when this channel is guaranteed not to be updated with new contents (e.g. on weekends).
Generator FeedGeneratorInformation about software used to generate the feed.
TextInput FeedTextInputDescribes a simple form – for example, used to search the main resource or find channel entries; RSS-only.
TTL integerTime-to-live – indicates how long (in minutes) this feed can be cached; RSS-only.
Cloud FeedCloudDefines the interface to a cloud subscribing protocol; RSS-only.

FeedEntry

FeedEntry inherits from FeedDescriptorFeedObjWithCommonAttrs; its properties:

Published timestampDate when this entry was published.
CommentsURL stringURL with user comments regarding this entry.
Source FeedContentRefers to the channel from which this entry was delivered or based on.
Content FeedContentActual entry content.

FeedDescriptor

FeedDescriptor inherits from FeedObjWithCommonAttrs and is a base class for FeedChannel and FeedEntry; its properties:

Title FeedTextChannel’s title or an entry headline.
Description FeedTextChannel’s description or an entry synopsis.
Copyright stringPlain text string describing channel or entry copyright information.
Links FeedLinksSet of related resources or pages such as full HTML version of the entry or the location of the site home; Atom-only.
Permalink stringURL of the channel home page or the full HTML entry page. If omitted, TextFeeder sets this to channel self link for channels and to entry URL (served by TextFeeder) for entries.
Authors array of FeedPersonAuthors of this channel or entry.
Author FeedPersonShorthand property for setting Authors (see above).
Contributors array of FeedPersonContributors of this channel or entry; Atom-only.
Contributor FeedPersonShorthand property for setting Contributors (see above); Atom-only.
Categories array of FeedCategoryList of categories this channel or entry belongs to (like «cats», «cars», «computers»).
Category FeedCategoryShorthand property for setting Categories (see above).
Updated timestampTime when this feed or entry was last updated.

FeedObjWithCommonAttrs

FeedObjWithCommonAttrs properties:

Language stringISO-639 language code like «en», «ru» or «en_US», «ru_RU».
BaseURL stringBase address prepended to all links, images and other entities referring to some resources. Usually points to the main site’s home; Atom-only (using xml:base).

Property format strings

Each Feeder object has an ability to assign properties from an array of strings or a single string. Array contains property keys like the ones described above plus an optional argument after a space; the format of values (strings) depends on the property being set.

TextFeeder allows setting of object proeprties based on YAML-style channel and entry definition files.

It’s also possible to assign values to objects of these classes using their PHPSetFromString('...') method:

PHP
$image = new FeedImage;
$image->SetFromString('50*100 http://example.com/image.jpg');

$feeder = new Feeder;
$feeder->Channel()->Image()->SetFromString('50*100 http://example.com/image.jpg');

The above is just a short notation for setting object properties directly:

PHP
$image = new FeedImage;
$image->Width(50);
$image->Height(100);
$image->ImageURL('http://example.com/image.jpg');

FeedText

FeedText inherits from FeedObjWithCommonAttrs; optional argument specifies case-insensitive text format (one of text, HTML, XHTML) which defaults to text. Example:

confDescription:    Plain text.

Description HTML: >
  <p>Markup is <em>fine</em>.</p>

When an unspecified format is requested FeedText attempts to transform the ones it has by quoting HTML in plain text to produce (X)HTML and by stripping HTML tags from an existing (X)HTML to produce its text representation.

FeedContent

FeedContent inherits from FeedTextFeedObjWithCommonAttrs; it has the same string format except that an URL instead of the actual content is allowed – for this start the value with the «at» symbol (@).

If you start the value with @@ it will be treated as a string with leading @ and the second one will be removed.

Content HTML:   @http://example.com/2012-03-12-this-entry/
Content:        @@This text content just starts with a single "at" symbol.

FeedLinks

FeedLinks is a collection of related channel or entry resources or the link to the feed itself. Optional argument specifies relation – one of alternate, related, self, enclosure, via. Value has the following format:

[text/html] http://example.com/page.html [18839] Title lasts until the end.

From left to right:

FeedImage

FeedImage inherits from FeedObjWithCommonAttrs; optional argument is unused; string has the following format:

[[Width][xX*][Height]] [height] http://example.com/picture.gif

From left to right:

FeedPerson

FeedImage inherits from FeedObjWithCommonAttrs; optional argument is unused; string has the following format:

[Joe Goth] [e@mail.com] [www.example.com]

If e-mail is present it separates the person’s name on the left and his home page on the right. If e-mail is omitted the entire string is treated as the person’s name unless it contains : or www. – in this case it’s split and the name is taken from the leading part while the rest goes to the URL:

http:// prefix is added to all URLs that don’t contain a colon (:).

FeedCategory

FeedImage inherits from FeedObjWithCommonAttrs; optional argument is unused; string has the following format:

[(http://|www.)example.com] Category [Label lasting until the end.]

From left to right:

FeedGenerator

FeedImage inherits from FeedObjWithCommonAttrs; optional argument is unused; string has the following format:

[http://|www.]homepage Name with spaces [v]1[.0]

Order of its parts doesn’t matter as they are unambiguously detected:

FeedTextInput

FeedTextInput defines a small channel form with a text input field and a button. Optional argument is unused; value has the following format:

(http://www.)URL input_name Caption lasting until the end.

From left to right:

FeedCloud

FeedCloud defines an interface to a cloud domain used to subscribe the user to new updates. Only supported by RSS. Optional argument is unused; value has the following format:

domain.ru [/]path/subscribe http-post [80] procedure

From left to right: