2 /***************************************************************************
4 FeedCreator class v1.7.2
5 originally (c) Kai Blankenhorn
8 v1.3 work by Scott Reynen (scott@randomchaos.com) and Kai Blankenhorn
9 v1.5 OPML support by Dirk Clemens
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2.1 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 ****************************************************************************
31 license changed to LGPL
35 fixed left over debug code
38 added HTML and JavaScript feeds (configurable via CSS) (thanks to Pascal Van Hecke)
39 added HTML descriptions for all feed formats (thanks to Pascal Van Hecke)
40 added a switch to select an external stylesheet (thanks to Pascal Van Hecke)
41 changed default content-type to application/xml
42 added character encoding setting
43 fixed numerous smaller bugs (thanks to Sören Fuhrmann of golem.de)
44 improved changing ATOM versions handling (thanks to August Trometer)
45 improved the UniversalFeedCreator's useCached method (thanks to Sören Fuhrmann of golem.de)
46 added charset output in HTTP headers (thanks to Sören Fuhrmann of golem.de)
47 added Slashdot namespace to RSS 1.0 (thanks to Sören Fuhrmann of golem.de)
50 added stylesheet to RSS 1.0 feeds
51 fixed generator comment (thanks Kevin L. Papendick and Tanguy Pruvot)
52 fixed RFC822 date bug (thanks Tanguy Pruvot)
53 added TimeZone customization for RFC8601 (thanks Tanguy Pruvot)
54 fixed Content-type could be empty (thanks Tanguy Pruvot)
55 fixed author/creator in RSS1.0 (thanks Tanguy Pruvot)
58 added Atom 0.3 support (not all features, though)
59 improved OPML 1.0 support (hopefully - added more elements)
60 added support for arbitrary additional elements (use with caution)
61 code beautification :-)
62 considered beta due to some internal changes
65 fixed some RSS 1.0 glitches (thanks to Stéphane Vanpoperynghe)
66 fixed some inconsistencies between documentation and code (thanks to Timothy Martin)
69 added support for OPML 1.0
70 added more documentation
73 optional feed saving and caching
74 improved documentation
78 renamed to FeedCreator, as it not only creates RSS anymore
79 added support for mbox
80 tentative support for echo/necho/atom/pie/???
83 intelligent auto-truncating of RSS 0.91 attributes
84 don't create some attributes when they're not set
85 documentation improved
86 fixed a real and a possible bug with date conversions
91 now includes most RSS 0.91 attributes
99 ***************************************************************************/
101 /*** GENERAL USAGE *********************************************************
103 include("feedcreator.class.php");
105 $rss = new UniversalFeedCreator();
106 $rss->useCached(); // use cached version if age<1 hour
107 $rss->title = "PHP news";
108 $rss->description = "daily news from the PHP scripting world";
111 $rss->descriptionTruncSize = 500;
112 $rss->descriptionHtmlSyndicated = true;
114 $rss->link = "http://www.dailyphp.net/news";
115 $rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"];
117 $image = new FeedImage();
118 $image->title = "dailyphp.net logo";
119 $image->url = "http://www.dailyphp.net/images/logo.gif";
120 $image->link = "http://www.dailyphp.net";
121 $image->description = "Feed provided by dailyphp.net. Click to visit.";
124 $image->descriptionTruncSize = 500;
125 $image->descriptionHtmlSyndicated = true;
127 $rss->image = $image;
129 // get your news items from somewhere, e.g. your database:
130 mysql_select_db($dbHost, $dbUser, $dbPass);
131 $res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");
132 while ($data = mysql_fetch_object($res)) {
133 $item = new FeedItem();
134 $item->title = $data->title;
135 $item->link = $data->url;
136 $item->description = $data->short;
139 item->descriptionTruncSize = 500;
140 item->descriptionHtmlSyndicated = true;
142 $item->date = $data->newsdate;
143 $item->source = "http://www.dailyphp.net";
144 $item->author = "John Doe";
146 $rss->addItem($item);
149 // valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated),
150 // MBOX, OPML, ATOM, ATOM0.3, HTML, JS
151 echo $rss->saveFeed("RSS1.0", "news/feed.xml");
154 ***************************************************************************
156 **************************************************************************/
158 // your local timezone, set to "" to disable or for GMT
159 define("TIME_ZONE","+01:00");
167 define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2");
172 * A FeedItem is a part of a FeedCreator feed.
174 * @author Kai Blankenhorn <kaib@bitfolge.de>
177 class FeedItem
extends HtmlDescribable
{
179 * Mandatory attributes of an item.
181 var $title, $description, $link;
184 * Optional attributes of an item.
186 var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator;
189 * Publishing date of an item. May be in one of the following formats:
192 * "Mon, 20 Jan 03 18:05:41 +0400"
193 * "20 Jan 03 18:05:41 +0000"
196 * "2003-01-20T18:05:41+04:00"
204 * Any additional elements to include as an assiciated array. All $key => $value pairs
205 * will be included unencoded in the feed item in the form
206 * <$key>$value</$key>
207 * Again: No encoding will be used! This means you can invalidate or enhance the feed
208 * if $value contains markup. This may be abused to embed tags not implemented by
209 * the FeedCreator class used.
211 var $additionalElements = Array();
220 * An FeedImage may be added to a FeedCreator feed.
221 * @author Kai Blankenhorn <kaib@bitfolge.de>
224 class FeedImage
extends HtmlDescribable
{
226 * Mandatory attributes of an image.
228 var $title, $url, $link;
231 * Optional attributes of an image.
233 var $width, $height, $description;
239 * An HtmlDescribable is an item within a feed that can have a description that may
240 * include HTML markup.
242 class HtmlDescribable
{
244 * Indicates whether the description field should be rendered in HTML.
246 var $descriptionHtmlSyndicated;
249 * Indicates whether and to how many characters a description should be truncated.
251 var $descriptionTruncSize;
254 * Returns a formatted description field, depending on descriptionHtmlSyndicated and
255 * $descriptionTruncSize properties
256 * @return string the formatted description
258 function getDescription() {
259 $descriptionField = new FeedHtmlField($this->description
);
260 $descriptionField->syndicateHtml
= $this->descriptionHtmlSyndicated
;
261 $descriptionField->truncSize
= $this->descriptionTruncSize
;
262 return $descriptionField->output();
269 * An FeedHtmlField describes and generates
270 * a feed, item or image html field (probably a description). Output is
271 * generated based on $truncSize, $syndicateHtml properties.
272 * @author Pascal Van Hecke <feedcreator.class.php@vanhecke.info>
275 class FeedHtmlField
{
277 * Mandatory attributes of a FeedHtmlField.
279 var $rawFieldContent;
282 * Optional attributes of a FeedHtmlField.
285 var $truncSize, $syndicateHtml;
288 * Creates a new instance of FeedHtmlField.
289 * @param $string: if given, sets the rawFieldContent property
291 function FeedHtmlField($parFieldContent) {
292 if ($parFieldContent) {
293 $this->rawFieldContent
= $parFieldContent;
299 * Creates the right output, depending on $truncSize, $syndicateHtml properties.
300 * @return string the formatted field
303 // when field available and syndicated in html we assume
304 // - valid html in $rawFieldContent and we enclose in CDATA tags
305 // - no truncation (truncating risks producing invalid html)
306 if (!$this->rawFieldContent
) {
308 } elseif ($this->syndicateHtml
) {
309 $result = "<![CDATA[".$this->rawFieldContent
."]]>";
311 if ($this->truncSize
and is_int($this->truncSize
)) {
312 $result = FeedCreator
::iTrunc(htmlspecialchars($this->rawFieldContent
),$this->truncSize
);
314 $result = htmlspecialchars($this->rawFieldContent
);
325 * UniversalFeedCreator lets you choose during runtime which
327 * For general usage of a feed class, see the FeedCreator class
328 * below or the example above.
331 * @author Kai Blankenhorn <kaib@bitfolge.de>
333 class UniversalFeedCreator
extends FeedCreator
{
336 function _setFormat($format) {
337 switch (strtoupper($format)) {
342 $this->_feed
= new RSSCreator20();
348 $this->_feed
= new RSSCreator10();
354 $this->_feed
= new RSSCreator091();
358 $this->_feed
= new PIECreator01();
362 $this->_feed
= new MBOXCreator();
366 $this->_feed
= new OPMLCreator();
370 // fall through: always the latest ATOM version
373 $this->_feed
= new AtomCreator03();
377 $this->_feed
= new HTMLCreator();
383 $this->_feed
= new JSCreator();
387 $this->_feed
= new RSSCreator091();
391 $vars = get_object_vars($this);
392 foreach ($vars as $key => $value) {
393 // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself
394 if (!in_array($key, array("_feed", "contentType", "encoding"))) {
395 $this->_feed
->{$key} = $this->{$key};
401 * Creates a syndication feed based on the items previously added.
403 * @see FeedCreator::addItem()
404 * @param string format format the feed should comply to. Valid values are:
405 * "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS"
406 * @return string the contents of the feed.
408 function createFeed($format = "RSS0.91") {
409 $this->_setFormat($format);
410 return $this->_feed
->createFeed();
416 * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect
417 * header may be sent to redirect the use to the newly created file.
420 * @param string format format the feed should comply to. Valid values are:
421 * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS"
422 * @param string filename optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
423 * @param boolean displayContents optional send the content of the file or not. If true, the file will be sent in the body of the response.
425 function saveFeed($format="RSS0.91", $filename="", $displayContents=true) {
426 $this->_setFormat($format);
427 $this->_feed
->saveFeed($filename, $displayContents);
432 * Turns on caching and checks if there is a recent version of this feed in the cache.
433 * If there is, an HTTP redirect header is sent.
434 * To effectively use caching, you should create the FeedCreator object and call this method
435 * before anything else, especially before you do the time consuming task to build the feed
436 * (web fetching, for example).
438 * @param string format format the feed should comply to. Valid values are:
439 * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3".
440 * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
441 * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
443 function useCached($format="RSS0.91", $filename="", $timeout=3600) {
444 $this->_setFormat($format);
445 $this->_feed
->useCached($filename, $timeout);
452 * FeedCreator is the abstract base implementation for concrete
453 * implementations that implement a specific format of syndication.
456 * @author Kai Blankenhorn <kaib@bitfolge.de>
459 class FeedCreator
extends HtmlDescribable
{
462 * Mandatory attributes of a feed.
464 var $title, $description, $link;
468 * Optional attributes of a feed.
470 var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays;
473 * The url of the external xsl stylesheet used to format the naked rss feed.
474 * Ignored in the output when empty.
476 var $xslStyleSheet = "";
482 var $items = Array();
486 * This feed's MIME content type.
490 var $contentType = "application/xml";
494 * This feed's character encoding.
497 var $encoding = "cp1250";
501 * Any additional elements to include as an assiciated array. All $key => $value pairs
502 * will be included unencoded in the feed in the form
503 * <$key>$value</$key>
504 * Again: No encoding will be used! This means you can invalidate or enhance the feed
505 * if $value contains markup. This may be abused to embed tags not implemented by
506 * the FeedCreator class used.
508 var $additionalElements = Array();
512 * Adds an FeedItem to the feed.
514 * @param object FeedItem $item The FeedItem to add to the feed.
517 function addItem($item) {
518 $this->items
[] = $item;
523 * Truncates a string to a certain length at the most sensible point.
524 * First, if there's a '.' character near the end of the string, the string is truncated after this character.
525 * If there is no '.', the string is truncated after the last ' ' character.
526 * If the string is truncated, " ..." is appended.
527 * If the string is already shorter than $length, it is returned unchanged.
530 * @param string string A string to be truncated.
531 * @param int length the maximum length the string should be truncated to
532 * @return string the truncated string
534 function iTrunc($string, $length) {
535 if (strlen($string)<=$length) {
539 $pos = strrpos($string,".");
540 if ($pos>=$length-4) {
541 $string = substr($string,0,$length-4);
542 $pos = strrpos($string,".");
544 if ($pos>=$length*0.4) {
545 return substr($string,0,$pos+
1)." ...";
548 $pos = strrpos($string," ");
549 if ($pos>=$length-4) {
550 $string = substr($string,0,$length-4);
551 $pos = strrpos($string," ");
553 if ($pos>=$length*0.4) {
554 return substr($string,0,$pos)." ...";
557 return substr($string,0,$length-4)." ...";
563 * Creates a comment indicating the generator of this feed.
564 * The format of this comment seems to be recognized by
567 function _createGeneratorComment() {
568 return "<!-- generator=\"".FEEDCREATOR_VERSION
."\" -->\n";
573 * Creates a string containing all additional elements specified in
574 * $additionalElements.
575 * @param elements array an associative array containing key => value pairs
576 * @param indentString string a string that will be inserted before every generated line
577 * @return string the XML tags corresponding to $additionalElements
579 function _createAdditionalElements($elements, $indentString="") {
581 if (is_array($elements)) {
582 foreach($elements AS $key => $value) {
583 $ae.= $indentString."<$key>$value</$key>\n";
589 function _createStylesheetReferences() {
591 if ($this->cssStyleSheet
) $xml .= "<?xml-stylesheet href=\"".$this->cssStyleSheet
."\" type=\"text/css\"?>\n";
592 if ($this->xslStyleSheet
) $xml .= "<?xml-stylesheet href=\"".$this->xslStyleSheet
."\" type=\"text/xsl\"?>\n";
598 * Builds the feed's text.
600 * @return string the feed's complete text
602 function createFeed() {
606 * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml.
609 * echo $_SERVER["PHP_SELF"]."\n";
610 * echo FeedCreator::_generateFilename();
614 * /rss/latestnews.php
617 * @return string the feed cache filename
621 function _generateFilename() {
622 $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
623 return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+
1)).".xml";
631 function _redirect($filename) {
632 // attention, heavily-commented-out-area
634 // maybe use this in addition to file time checking
635 //Header("Expires: ".date("r",time()+$this->_timeout));
637 /* no caching at all, doesn't seem to work as good:
638 Header("Cache-Control: no-cache");
639 Header("Pragma: no-cache");
642 // HTTP redirect, some feed readers' simple HTTP implementations don't follow it
643 //Header("Location: ".$filename);
645 Header("Content-Type: ".$this->contentType
."; charset=".$this->encoding
."; filename=".basename($filename));
646 Header("Content-Disposition: inline; filename=".basename($filename));
647 readfile($filename, "r");
652 * Turns on caching and checks if there is a recent version of this feed in the cache.
653 * If there is, an HTTP redirect header is sent.
654 * To effectively use caching, you should create the FeedCreator object and call this method
655 * before anything else, especially before you do the time consuming task to build the feed
656 * (web fetching, for example).
658 * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
659 * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
661 function useCached($filename="", $timeout=3600) {
662 $this->_timeout
= $timeout;
664 $filename = $this->_generateFilename();
666 if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) {
667 $this->_redirect($filename);
673 * Saves this feed as a file on the local disk. After the file is saved, a redirect
674 * header may be sent to redirect the user to the newly created file.
677 * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
678 * @param redirect boolean optional send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file.
680 function saveFeed($filename="", $displayContents=true) {
682 $filename = $this->_generateFilename();
684 $feedFile = fopen($filename, "w+");
686 fputs($feedFile,$this->createFeed());
688 if ($displayContents) {
689 $this->_redirect($filename);
692 echo "<br /><b>Error creating feed file, please check write permissions.</b><br />";
696 function showFeed($format)
698 echo $this->createFeed($format);
705 * FeedDate is an internal class that stores a date for a feed or feed item.
706 * Usually, you won't need to use this.
712 * Creates a new instance of FeedDate representing a given date.
713 * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps.
714 * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used.
716 function FeedDate($dateString="") {
717 if ($dateString=="") $dateString = date("r");
719 if (is_integer($dateString)) {
720 $this->unix
= $dateString;
723 if (preg_match("~(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?(\\d{1,2})\\s+([a-zA-Z]{3})\\s+(\\d{4})\\s+(\\d{2}):(\\d{2}):(\\d{2})\\s+(.*)~",$dateString,$matches)) {
724 $months = Array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12);
725 $this->unix
= mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]);
726 if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
727 $tzOffset = (substr($matches[7],0,3) * 60 +
substr($matches[7],-2)) * 60;
729 if (strlen($matches[7])==1) {
731 $ord = ord($matches[7]);
732 if ($ord < ord("M")) {
733 $tzOffset = (ord("A") - $ord - 1) * $oneHour;
734 } elseif ($ord >= ord("M") AND $matches[7]!="Z") {
735 $tzOffset = ($ord - ord("M")) * $oneHour;
736 } elseif ($matches[7]=="Z") {
740 switch ($matches[7]) {
742 case "GMT": $tzOffset = 0;
745 $this->unix +
= $tzOffset;
748 if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) {
749 $this->unix
= mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]);
750 if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
751 $tzOffset = (substr($matches[7],0,3) * 60 +
substr($matches[7],-2)) * 60;
753 if ($matches[7]=="Z") {
757 $this->unix +
= $tzOffset;
764 * Gets the date stored in this FeedDate as an RFC 822 date.
766 * @return a date in RFC 822 format
769 //return gmdate("r",$this->unix);
770 $date = gmdate("D, d M Y H:i:s", $this->unix
);
771 if (TIME_ZONE
!="") $date .= " ".str_replace(":","",TIME_ZONE
);
776 * Gets the date stored in this FeedDate as an ISO 8601 date.
778 * @return a date in ISO 8601 format
781 $date = gmdate("Y-m-d\TH:i:sO",$this->unix
);
782 $date = substr($date,0,22) . ':' . substr($date,-2);
783 if (TIME_ZONE
!="") $date = str_replace("+00:00",TIME_ZONE
,$date);
788 * Gets the date stored in this FeedDate as unix time stamp.
790 * @return a date as a unix time stamp
799 * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0.
801 * @see http://www.purl.org/rss/1.0/
803 * @author Kai Blankenhorn <kaib@bitfolge.de>
805 class RSSCreator10
extends FeedCreator
{
808 * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
809 * The feed will contain all items previously added in the same order.
810 * @return string the feed's complete text
812 function createFeed() {
813 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding
."\"?>\n";
814 $feed.= $this->_createGeneratorComment();
815 if ($this->cssStyleSheet
=="") {
816 $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css";
818 $feed.= $this->_createStylesheetReferences();
819 $feed.= "<rdf:RDF\n";
820 $feed.= " xmlns=\"http://purl.org/rss/1.0/\"\n";
821 $feed.= " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n";
822 $feed.= " xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n";
823 $feed.= " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
824 $feed.= " <channel rdf:about=\"".$this->syndicationURL
."\">\n";
825 $feed.= " <title>".htmlspecialchars($this->title
)."</title>\n";
826 $feed.= " <description>".htmlspecialchars($this->description
)."</description>\n";
827 $feed.= " <link>".$this->link
."</link>\n";
828 if ($this->image
!=null) {
829 $feed.= " <image rdf:resource=\"".$this->image
->url
."\" />\n";
831 $now = new FeedDate();
832 $feed.= " <dc:date>".htmlspecialchars($now->iso8601())."</dc:date>\n";
833 $feed.= " <items>\n";
834 $feed.= " <rdf:Seq>\n";
835 for ($i=0;$i<count($this->items
);$i++
) {
836 $feed.= " <rdf:li rdf:resource=\"".htmlspecialchars($this->items
[$i]->link
)."\"/>\n";
838 $feed.= " </rdf:Seq>\n";
839 $feed.= " </items>\n";
840 $feed.= " </channel>\n";
841 if ($this->image
!=null) {
842 $feed.= " <image rdf:about=\"".$this->image
->url
."\">\n";
843 $feed.= " <title>".$this->image
->title
."</title>\n";
844 $feed.= " <link>".$this->image
->link
."</link>\n";
845 $feed.= " <url>".$this->image
->url
."</url>\n";
846 $feed.= " </image>\n";
848 $feed.= $this->_createAdditionalElements($this->additionalElements
, " ");
850 for ($i=0;$i<count($this->items
);$i++
) {
851 $feed.= " <item rdf:about=\"".htmlspecialchars($this->items
[$i]->link
)."\">\n";
852 //$feed.= " <dc:type>Posting</dc:type>\n";
853 $feed.= " <dc:format>text/html</dc:format>\n";
854 if ($this->items
[$i]->date
!=null) {
855 $itemDate = new FeedDate($this->items
[$i]->date
);
856 $feed.= " <dc:date>".htmlspecialchars($itemDate->iso8601())."</dc:date>\n";
858 if ($this->items
[$i]->source
!="") {
859 $feed.= " <dc:source>".htmlspecialchars($this->items
[$i]->source
)."</dc:source>\n";
861 if ($this->items
[$i]->author
!="") {
862 $feed.= " <dc:creator>".htmlspecialchars($this->items
[$i]->author
)."</dc:creator>\n";
864 $feed.= " <title>".htmlspecialchars(strip_tags(strtr($this->items
[$i]->title
,"\n\r"," ")))."</title>\n";
865 $feed.= " <link>".htmlspecialchars($this->items
[$i]->link
)."</link>\n";
866 $feed.= " <description>".htmlspecialchars($this->items
[$i]->description
)."</description>\n";
867 $feed.= $this->_createAdditionalElements($this->items
[$i]->additionalElements
, " ");
868 $feed.= " </item>\n";
870 $feed.= "</rdf:RDF>\n";
878 * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3.
880 * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html
882 * @author Kai Blankenhorn <kaib@bitfolge.de>
884 class RSSCreator091
extends FeedCreator
{
887 * Stores this RSS feed's version number.
892 function RSSCreator091() {
893 $this->_setRSSVersion("0.91");
894 $this->contentType
= "application/rss+xml";
898 * Sets this RSS feed's version number.
901 function _setRSSVersion($version) {
902 $this->RSSVersion
= $version;
906 * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
907 * The feed will contain all items previously added in the same order.
908 * @return string the feed's complete text
910 function createFeed() {
911 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding
."\"?>\n";
912 $feed.= $this->_createGeneratorComment();
913 $feed.= $this->_createStylesheetReferences();
914 $feed.= "<rss version=\"".$this->RSSVersion
."\">\n";
915 $feed.= " <channel>\n";
916 $feed.= " <title>".FeedCreator
::iTrunc(htmlspecialchars($this->title
),100)."</title>\n";
917 $this->descriptionTruncSize
= 500;
918 $feed.= " <description>".$this->getDescription()."</description>\n";
919 $feed.= " <link>".$this->link
."</link>\n";
920 $now = new FeedDate();
921 $feed.= " <lastBuildDate>".htmlspecialchars($now->rfc822())."</lastBuildDate>\n";
922 $feed.= " <generator>".FEEDCREATOR_VERSION
."</generator>\n";
924 if ($this->image
!=null) {
925 $feed.= " <image>\n";
926 $feed.= " <url>".$this->image
->url
."</url>\n";
927 $feed.= " <title>".FeedCreator
::iTrunc(htmlspecialchars($this->image
->title
),100)."</title>\n";
928 $feed.= " <link>".$this->image
->link
."</link>\n";
929 if ($this->image
->width
!="") {
930 $feed.= " <width>".$this->image
->width
."</width>\n";
932 if ($this->image
->height
!="") {
933 $feed.= " <height>".$this->image
->height
."</height>\n";
935 if ($this->image
->description
!="") {
936 $feed.= " <description>".$this->image
->getDescription()."</description>\n";
938 $feed.= " </image>\n";
940 if ($this->language
!="") {
941 $feed.= " <language>".$this->language
."</language>\n";
943 if ($this->copyright
!="") {
944 $feed.= " <copyright>".FeedCreator
::iTrunc(htmlspecialchars($this->copyright
),100)."</copyright>\n";
946 if ($this->editor
!="") {
947 $feed.= " <managingEditor>".FeedCreator
::iTrunc(htmlspecialchars($this->editor
),100)."</managingEditor>\n";
949 if ($this->webmaster
!="") {
950 $feed.= " <webMaster>".FeedCreator
::iTrunc(htmlspecialchars($this->webmaster
),100)."</webMaster>\n";
952 if ($this->pubDate
!="") {
953 $pubDate = new FeedDate($this->pubDate
);
954 $feed.= " <pubDate>".htmlspecialchars($pubDate->rfc822())."</pubDate>\n";
956 if ($this->category
!="") {
957 $feed.= " <category>".htmlspecialchars($this->category
)."</category>\n";
959 if ($this->docs
!="") {
960 $feed.= " <docs>".FeedCreator
::iTrunc(htmlspecialchars($this->docs
),500)."</docs>\n";
962 if ($this->ttl
!="") {
963 $feed.= " <ttl>".htmlspecialchars($this->ttl
)."</ttl>\n";
965 if ($this->rating
!="") {
966 $feed.= " <rating>".FeedCreator
::iTrunc(htmlspecialchars($this->rating
),500)."</rating>\n";
968 if ($this->skipHours
!="") {
969 $feed.= " <skipHours>".htmlspecialchars($this->skipHours
)."</skipHours>\n";
971 if ($this->skipDays
!="") {
972 $feed.= " <skipDays>".htmlspecialchars($this->skipDays
)."</skipDays>\n";
974 $feed.= $this->_createAdditionalElements($this->additionalElements
, " ");
976 for ($i=0;$i<count($this->items
);$i++
) {
978 $feed.= " <title>".FeedCreator
::iTrunc(htmlspecialchars(strip_tags($this->items
[$i]->title
)),100)."</title>\n";
979 $feed.= " <link>".htmlspecialchars($this->items
[$i]->link
)."</link>\n";
980 $feed.= " <description>".$this->items
[$i]->getDescription()."</description>\n";
982 if ($this->items
[$i]->author
!="") {
983 $feed.= " <author>".htmlspecialchars($this->items
[$i]->author
)."</author>\n";
987 if ($this->items[$i]->source!="") {
988 $feed.= " <source>".htmlspecialchars($this->items[$i]->source)."</source>\n";
991 if ($this->items
[$i]->category
!="") {
992 $feed.= " <category>".htmlspecialchars($this->items
[$i]->category
)."</category>\n";
994 if ($this->items
[$i]->comments
!="") {
995 $feed.= " <comments>".htmlspecialchars($this->items
[$i]->comments
)."</comments>\n";
997 if ($this->items
[$i]->date
!="") {
998 $itemDate = new FeedDate($this->items
[$i]->date
);
999 $feed.= " <pubDate>".htmlspecialchars($itemDate->rfc822())."</pubDate>\n";
1001 if ($this->items
[$i]->guid
!="") {
1002 $feed.= " <guid>".htmlspecialchars($this->items
[$i]->guid
)."</guid>\n";
1004 $feed.= $this->_createAdditionalElements($this->items
[$i]->additionalElements
, " ");
1005 $feed.= " </item>\n";
1007 $feed.= " </channel>\n";
1016 * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0.
1018 * @see http://backend.userland.com/rss
1020 * @author Kai Blankenhorn <kaib@bitfolge.de>
1022 class RSSCreator20
extends RSSCreator091
{
1024 function RSSCreator20() {
1025 parent
::_setRSSVersion("2.0");
1032 * PIECreator01 is a FeedCreator that implements the emerging PIE specification,
1033 * as in http://intertwingly.net/wiki/pie/Syntax.
1037 * @author Scott Reynen <scott@randomchaos.com> and Kai Blankenhorn <kaib@bitfolge.de>
1039 class PIECreator01
extends FeedCreator
{
1041 function PIECreator01() {
1042 $this->encoding
= "utf-8";
1045 function createFeed() {
1046 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding
."\"?>\n";
1047 $feed.= $this->_createStylesheetReferences();
1048 $feed.= "<feed version=\"0.1\" xmlns=\"http://example.com/newformat#\">\n";
1049 $feed.= " <title>".FeedCreator
::iTrunc(htmlspecialchars($this->title
),100)."</title>\n";
1050 $this->truncSize
= 500;
1051 $feed.= " <subtitle>".$this->getDescription()."</subtitle>\n";
1052 $feed.= " <link>".$this->link
."</link>\n";
1053 for ($i=0;$i<count($this->items
);$i++
) {
1054 $feed.= " <entry>\n";
1055 $feed.= " <title>".FeedCreator
::iTrunc(htmlspecialchars(strip_tags($this->items
[$i]->title
)),100)."</title>\n";
1056 $feed.= " <link>".htmlspecialchars($this->items
[$i]->link
)."</link>\n";
1057 $itemDate = new FeedDate($this->items
[$i]->date
);
1058 $feed.= " <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1059 $feed.= " <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1060 $feed.= " <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1061 $feed.= " <id>".htmlspecialchars($this->items
[$i]->guid
)."</id>\n";
1062 if ($this->items
[$i]->author
!="") {
1063 $feed.= " <author>\n";
1064 $feed.= " <name>".htmlspecialchars($this->items
[$i]->author
)."</name>\n";
1065 if ($this->items
[$i]->authorEmail
!="") {
1066 $feed.= " <email>".$this->items
[$i]->authorEmail
."</email>\n";
1068 $feed.=" </author>\n";
1070 $feed.= " <content type=\"text/html\" xml:lang=\"en-us\">\n";
1071 $feed.= " <div xmlns=\"http://www.w3.org/1999/xhtml\">".$this->items
[$i]->getDescription()."</div>\n";
1072 $feed.= " </content>\n";
1073 $feed.= " </entry>\n";
1075 $feed.= "</feed>\n";
1082 * AtomCreator03 is a FeedCreator that implements the atom specification,
1083 * as in http://www.intertwingly.net/wiki/pie/FrontPage.
1084 * Please note that just by using AtomCreator03 you won't automatically
1085 * produce valid atom files. For example, you have to specify either an editor
1086 * for the feed or an author for every single feed item.
1088 * Some elements have not been implemented yet. These are (incomplete list):
1089 * author URL, item author's email and URL, item contents, alternate links,
1090 * other link content types than text/html. Some of them may be created with
1091 * AtomCreator03::additionalElements.
1093 * @see FeedCreator#additionalElements
1095 * @author Kai Blankenhorn <kaib@bitfolge.de>, Scott Reynen <scott@randomchaos.com>
1097 class AtomCreator03
extends FeedCreator
{
1099 function AtomCreator03() {
1100 $this->contentType
= "application/atom+xml";
1101 $this->encoding
= "utf-8";
1104 function createFeed() {
1105 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding
."\"?>\n";
1106 $feed.= $this->_createGeneratorComment();
1107 $feed.= $this->_createStylesheetReferences();
1108 $feed.= "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\"";
1109 if ($this->language
!="") {
1110 $feed.= " xml:lang=\"".$this->language
."\"";
1113 $feed.= " <title>".htmlspecialchars($this->title
)."</title>\n";
1114 $feed.= " <tagline>".htmlspecialchars($this->description
)."</tagline>\n";
1115 $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link
)."\"/>\n";
1116 $feed.= " <id>".htmlspecialchars($this->link
)."</id>\n";
1117 $now = new FeedDate();
1118 $feed.= " <modified>".htmlspecialchars($now->iso8601())."</modified>\n";
1119 if ($this->editor
!="") {
1120 $feed.= " <author>\n";
1121 $feed.= " <name>".$this->editor
."</name>\n";
1122 if ($this->editorEmail
!="") {
1123 $feed.= " <email>".$this->editorEmail
."</email>\n";
1125 $feed.= " </author>\n";
1127 $feed.= " <generator>".FEEDCREATOR_VERSION
."</generator>\n";
1128 $feed.= $this->_createAdditionalElements($this->additionalElements
, " ");
1129 for ($i=0;$i<count($this->items
);$i++
) {
1130 $feed.= " <entry>\n";
1131 $feed.= " <title>".htmlspecialchars(strip_tags($this->items
[$i]->title
))."</title>\n";
1132 $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items
[$i]->link
)."\"/>\n";
1133 if ($this->items
[$i]->date
=="") {
1134 $this->items
[$i]->date
= time();
1136 $itemDate = new FeedDate($this->items
[$i]->date
);
1137 $feed.= " <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1138 $feed.= " <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1139 $feed.= " <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1140 $feed.= " <id>".htmlspecialchars($this->items
[$i]->link
)."</id>\n";
1141 $feed.= $this->_createAdditionalElements($this->items
[$i]->additionalElements
, " ");
1142 if ($this->items
[$i]->author
!="") {
1143 $feed.= " <author>\n";
1144 $feed.= " <name>".htmlspecialchars($this->items
[$i]->author
)."</name>\n";
1145 $feed.= " </author>\n";
1147 if ($this->items
[$i]->description
!="") {
1148 $feed.= " <summary>".htmlspecialchars($this->items
[$i]->description
)."</summary>\n";
1150 $feed.= " </entry>\n";
1152 $feed.= "</feed>\n";
1159 * MBOXCreator is a FeedCreator that implements the mbox format
1160 * as described in http://www.qmail.org/man/man5/mbox.html
1163 * @author Kai Blankenhorn <kaib@bitfolge.de>
1165 class MBOXCreator
extends FeedCreator
{
1167 function MBOXCreator() {
1168 $this->contentType
= "text/plain";
1169 $this->encoding
= "ISO-8859-15";
1172 function qp_enc($input = "", $line_max = 76) {
1173 $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1174 $lines = preg_split("/(?:\r\n|\r|\n)/", $input);
1178 while( list(, $line) = each($lines) ) {
1179 //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary
1180 $linlen = strlen($line);
1182 for($i = 0; $i < $linlen; $i++
) {
1183 $c = substr($line, $i, 1);
1185 if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only
1187 } elseif ( ($dec == 61) ||
($dec < 32 ) ||
($dec > 126) ) { // always encode "\t", which is *not* required
1188 $h2 = floor($dec/16); $h1 = floor($dec%16
);
1189 $c = $escape.$hex["$h2"].$hex["$h1"];
1191 if ( (strlen($newline) +
strlen($c)) >= $line_max ) { // CRLF is not counted
1192 $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
1197 $output .= $newline.$eol;
1199 return trim($output);
1204 * Builds the MBOX contents.
1205 * @return string the feed's complete text
1207 function createFeed() {
1208 for ($i=0;$i<count($this->items
);$i++
) {
1209 if ($this->items
[$i]->author
!="") {
1210 $from = $this->items
[$i]->author
;
1212 $from = $this->title
;
1214 $itemDate = new FeedDate($this->items
[$i]->date
);
1215 $feed.= "From ".strtr(MBOXCreator
::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n";
1216 $feed.= "Content-Type: text/plain;\n";
1217 $feed.= " charset=\"".$this->encoding
."\"\n";
1218 $feed.= "Content-Transfer-Encoding: quoted-printable\n";
1219 $feed.= "Content-Type: text/plain\n";
1220 $feed.= "From: \"".MBOXCreator
::qp_enc($from)."\"\n";
1221 $feed.= "Date: ".$itemDate->rfc822()."\n";
1222 $feed.= "Subject: ".MBOXCreator
::qp_enc(FeedCreator
::iTrunc($this->items
[$i]->title
,100))."\n";
1224 $body = chunk_split(MBOXCreator
::qp_enc($this->items
[$i]->description
));
1225 $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body);
1233 * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types.
1234 * @return string the feed cache filename
1238 function _generateFilename() {
1239 $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1240 return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+
1)).".mbox";
1246 * OPMLCreator is a FeedCreator that implements OPML 1.0.
1248 * @see http://opml.scripting.com/spec
1249 * @author Dirk Clemens, Kai Blankenhorn
1252 class OPMLCreator
extends FeedCreator
{
1254 function OPMLCreator() {
1255 $this->encoding
= "cp1250";
1258 function createFeed() {
1259 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding
."\"?>\n";
1260 $feed.= $this->_createGeneratorComment();
1261 $feed.= $this->_createStylesheetReferences();
1262 $feed.= "<opml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
1263 $feed.= " <head>\n";
1264 $feed.= " <title>".htmlspecialchars($this->title
)."</title>\n";
1265 if ($this->pubDate
!="") {
1266 $date = new FeedDate($this->pubDate
);
1267 $feed.= " <dateCreated>".$date->rfc822()."</dateCreated>\n";
1269 if ($this->lastBuildDate
!="") {
1270 $date = new FeedDate($this->lastBuildDate
);
1271 $feed.= " <dateModified>".$date->rfc822()."</dateModified>\n";
1273 if ($this->editor
!="") {
1274 $feed.= " <ownerName>".$this->editor
."</ownerName>\n";
1276 if ($this->editorEmail
!="") {
1277 $feed.= " <ownerEmail>".$this->editorEmail
."</ownerEmail>\n";
1279 $feed.= " </head>\n";
1280 $feed.= " <body>\n";
1281 for ($i=0;$i<count($this->items
);$i++
) {
1282 $feed.= " <outline type=\"rss\" ";
1283 $title = htmlspecialchars(strip_tags(strtr($this->items
[$i]->title
,"\n\r"," ")));
1284 $feed.= " title=\"".$title."\"";
1285 $feed.= " text=\"".$title."\"";
1286 //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\"";
1287 $feed.= " url=\"".htmlspecialchars($this->items
[$i]->link
)."\"";
1290 $feed.= " </body>\n";
1291 $feed.= "</opml>\n";
1299 * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific
1300 * location, overriding the createFeed method of the parent FeedCreator.
1301 * The HTML produced can be included over http by scripting languages, or serve
1302 * as the source for an IFrame.
1303 * All output by this class is embedded in <div></div> tags to enable formatting
1306 * @author Pascal Van Hecke
1309 class HTMLCreator
extends FeedCreator
{
1311 var $contentType = "text/html";
1314 * Contains HTML to be output at the start of the feed's html representation.
1319 * Contains HTML to be output at the end of the feed's html representation.
1324 * Contains HTML to be output between entries. A separator is only used in
1325 * case of multiple entries.
1330 * Used to prefix the stylenames to make sure they are unique
1331 * and do not clash with stylenames on the users' page.
1336 * Determines whether the links open in a new window or not.
1338 var $openInNewWindow = true;
1340 var $imageAlign ="right";
1343 * In case of very simple output you may want to get rid of the style tags,
1344 * hence this variable. There's no equivalent on item level, but of course you can
1345 * add strings to it while iterating over the items ($this->stylelessOutput .= ...)
1346 * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored
1347 * in the function createFeed().
1349 var $stylelessOutput ="";
1353 * @return string the scripts's complete text
1355 function createFeed() {
1356 // if there is styleless output, use the content of this variable and ignore the rest
1357 if ($this->stylelessOutput
!="") {
1358 return $this->stylelessOutput
;
1361 //if no stylePrefix is set, generate it yourself depending on the script name
1362 if ($this->stylePrefix
=="") {
1363 $this->stylePrefix
= str_replace(".", "_", $this->_generateFilename())."_";
1366 //set an openInNewWindow_token_to be inserted or not
1367 if ($this->openInNewWindow
) {
1368 $targetInsert = " target='_blank'";
1371 // use this array to put the lines in and implode later with "document.write" javascript
1372 $feedArray = array();
1373 if ($this->image
!=null) {
1374 $imageStr = "<a href='".$this->image
->link
."'".$targetInsert.">".
1375 "<img src='".$this->image
->url
."' border='0' alt='".
1376 FeedCreator
::iTrunc(htmlspecialchars($this->image
->title
),100).
1377 "' align='".$this->imageAlign
."' ";
1378 if ($this->image
->width
) {
1379 $imageStr .=" width='".$this->image
->width
. "' ";
1381 if ($this->image
->height
) {
1382 $imageStr .=" height='".$this->image
->height
."' ";
1384 $imageStr .="/></a>";
1385 $feedArray[] = $imageStr;
1389 $feedArray[] = "<div class='".$this->stylePrefix
."title'><a href='".$this->link
."' ".$targetInsert." class='".$this->stylePrefix
."title'>".
1390 FeedCreator
::iTrunc(htmlspecialchars($this->title
),100)."</a></div>";
1392 if ($this->getDescription()) {
1393 $feedArray[] = "<div class='".$this->stylePrefix
."description'>".
1394 str_replace("]]>", "", str_replace("<![CDATA[", "", $this->getDescription())).
1398 if ($this->header
) {
1399 $feedArray[] = "<div class='".$this->stylePrefix
."header'>".$this->header
."</div>";
1402 for ($i=0;$i<count($this->items
);$i++
) {
1403 if ($this->separator
and $i > 0) {
1404 $feedArray[] = "<div class='".$this->stylePrefix
."separator'>".$this->separator
."</div>";
1407 if ($this->items
[$i]->title
) {
1408 if ($this->items
[$i]->link
) {
1410 "<div class='".$this->stylePrefix
."item_title'><a href='".$this->items
[$i]->link
."' class='".$this->stylePrefix
.
1411 "item_title'".$targetInsert.">".FeedCreator
::iTrunc(htmlspecialchars(strip_tags($this->items
[$i]->title
)),100).
1415 "<div class='".$this->stylePrefix
."item_title'>".
1416 FeedCreator
::iTrunc(htmlspecialchars(strip_tags($this->items
[$i]->title
)),100).
1420 if ($this->items
[$i]->getDescription()) {
1422 "<div class='".$this->stylePrefix
."item_description'>".
1423 str_replace("]]>", "", str_replace("<![CDATA[", "", $this->items
[$i]->getDescription())).
1427 if ($this->footer
) {
1428 $feedArray[] = "<div class='".$this->stylePrefix
."footer'>".$this->footer
."</div>";
1431 $feed= "".join($feedArray, "\r\n");
1436 * Overrrides parent to produce .html extensions
1438 * @return string the feed cache filename
1442 function _generateFilename() {
1443 $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1444 return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+
1)).".html";
1450 * JSCreator is a class that writes a js file to a specific
1451 * location, overriding the createFeed method of the parent HTMLCreator.
1453 * @author Pascal Van Hecke
1455 class JSCreator
extends HTMLCreator
{
1456 var $contentType = "text/javascript";
1459 * writes the javascript
1460 * @return string the scripts's complete text
1462 function createFeed()
1464 $feed = parent
::createFeed();
1465 $feedArray = explode("\n",$feed);
1468 foreach ($feedArray as $value) {
1469 $jsFeed .= "document.write('".trim(addslashes($value))."');\n";
1475 * Overrrides parent to produce .js extensions
1477 * @return string the feed cache filename
1481 function _generateFilename() {
1482 $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1483 return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+
1)).".js";
1490 /*** TEST SCRIPT *********************************************************
1492 //include("feedcreator.class.php");
1494 $rss = new UniversalFeedCreator();
1496 $rss->title = "PHP news";
1497 $rss->description = "daily news from the PHP scripting world";
1500 //$rss->descriptionTruncSize = 500;
1501 //$rss->descriptionHtmlSyndicated = true;
1502 //$rss->xslStyleSheet = "http://feedster.com/rss20.xsl";
1504 $rss->link = "http://www.dailyphp.net/news";
1505 $rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF;
1507 $image = new FeedImage();
1508 $image->title = "dailyphp.net logo";
1509 $image->url = "http://www.dailyphp.net/images/logo.gif";
1510 $image->link = "http://www.dailyphp.net";
1511 $image->description = "Feed provided by dailyphp.net. Click to visit.";
1514 $image->descriptionTruncSize = 500;
1515 $image->descriptionHtmlSyndicated = true;
1517 $rss->image = $image;
1519 // get your news items from somewhere, e.g. your database:
1520 //mysql_select_db($dbHost, $dbUser, $dbPass);
1521 //$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");
1522 //while ($data = mysql_fetch_object($res)) {
1523 $item = new FeedItem();
1524 $item->title = "This is an the test title of an item";
1525 $item->link = "http://localhost/item/";
1526 $item->description = "<b>description in </b><br/>HTML";
1529 //item->descriptionTruncSize = 500;
1530 $item->descriptionHtmlSyndicated = true;
1532 $item->date = time();
1533 $item->source = "http://www.dailyphp.net";
1534 $item->author = "John Doe";
1536 $rss->addItem($item);
1539 // valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS
1540 echo $rss->saveFeed("RSS0.91", "feed.xml");
1544 ***************************************************************************/