[ Index ]

PHP Cross Reference of Mambo 4.6.5

[ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/includes/ -> feedcreator.class.php (source)

   1  <?php
   2  /***************************************************************************

   3  

   4  FeedCreator class v1.7.2

   5  originally (c) Kai Blankenhorn

   6  www.bitfolge.de

   7  kaib@bitfolge.de

   8  v1.3 work by Scott Reynen (scott@randomchaos.com) and Kai Blankenhorn

   9  v1.5 OPML support by Dirk Clemens

  10  

  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.

  15  

  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.

  20  

  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

  24  

  25  ****************************************************************************

  26  

  27  

  28  Changelog:

  29  13-04-2006 Neil Thompson (neilt)

  30      added functionality for Atom 1.0

  31  

  32  v1.7.2    10-11-04

  33      license changed to LGPL

  34  

  35  v1.7.1

  36      fixed a syntax bug

  37      fixed left over debug code

  38  

  39  v1.7    07-18-04

  40      added HTML and JavaScript feeds (configurable via CSS) (thanks to Pascal Van Hecke)

  41      added HTML descriptions for all feed formats (thanks to Pascal Van Hecke)

  42      added a switch to select an external stylesheet (thanks to Pascal Van Hecke)

  43      changed default content-type to application/xml

  44      added character encoding setting

  45      fixed numerous smaller bugs (thanks to Sören Fuhrmann of golem.de)

  46      improved changing ATOM versions handling (thanks to August Trometer)

  47      improved the UniversalFeedCreator's useCached method (thanks to Sören Fuhrmann of golem.de)

  48      added charset output in HTTP headers (thanks to Sören Fuhrmann of golem.de)

  49      added Slashdot namespace to RSS 1.0 (thanks to Sören Fuhrmann of golem.de)

  50  

  51  v1.6    05-10-04

  52      added stylesheet to RSS 1.0 feeds

  53      fixed generator comment (thanks Kevin L. Papendick and Tanguy Pruvot)

  54      fixed RFC822 date bug (thanks Tanguy Pruvot)

  55      added TimeZone customization for RFC8601 (thanks Tanguy Pruvot)

  56      fixed Content-type could be empty (thanks Tanguy Pruvot)

  57      fixed author/creator in RSS1.0 (thanks Tanguy Pruvot)

  58  

  59  v1.6 beta    02-28-04

  60      added Atom 0.3 support (not all features, though)

  61      improved OPML 1.0 support (hopefully - added more elements)

  62      added support for arbitrary additional elements (use with caution)

  63      code beautification :-)

  64      considered beta due to some internal changes

  65  

  66  v1.5.1    01-27-04

  67      fixed some RSS 1.0 glitches (thanks to Stéphane Vanpoperynghe)

  68      fixed some inconsistencies between documentation and code (thanks to Timothy Martin)

  69  

  70  v1.5    01-06-04

  71      added support for OPML 1.0

  72      added more documentation

  73  

  74  v1.4    11-11-03

  75      optional feed saving and caching

  76      improved documentation

  77      minor improvements

  78  

  79  v1.3    10-02-03

  80      renamed to FeedCreator, as it not only creates RSS anymore

  81      added support for mbox

  82      tentative support for echo/necho/atom/pie/???

  83  

  84  v1.2    07-20-03

  85      intelligent auto-truncating of RSS 0.91 attributes

  86      don't create some attributes when they're not set

  87      documentation improved

  88      fixed a real and a possible bug with date conversions

  89      code cleanup

  90  

  91  v1.1    06-29-03

  92      added images to feeds

  93      now includes most RSS 0.91 attributes

  94      added RSS 2.0 feeds

  95  

  96  v1.0    06-24-03

  97      initial release

  98  

  99  

 100  

 101  ***************************************************************************/
 102  
 103  /*** GENERAL USAGE *********************************************************

 104  

 105  include("feedcreator.class.php");

 106  

 107  $rss = new UniversalFeedCreator();

 108  $rss->useCached(); // use cached version if age<1 hour

 109  $rss->title = "PHP news";

 110  $rss->description = "daily news from the PHP scripting world";

 111  

 112  //optional

 113  $rss->descriptionTruncSize = 500;

 114  $rss->descriptionHtmlSyndicated = true;

 115  

 116  $rss->link = "http://www.dailyphp.net/news";

 117  $rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"];

 118  

 119  $image = new FeedImage();

 120  $image->title = "dailyphp.net logo";

 121  $image->url = "http://www.dailyphp.net/images/logo.gif";

 122  $image->link = "http://www.dailyphp.net";

 123  $image->description = "Feed provided by dailyphp.net. Click to visit.";

 124  

 125  //optional

 126  $image->descriptionTruncSize = 500;

 127  $image->descriptionHtmlSyndicated = true;

 128  

 129  $rss->image = $image;

 130  

 131  // get your news items from somewhere, e.g. your database:

 132  mysql_select_db($dbHost, $dbUser, $dbPass);

 133  $res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");

 134  while ($data = mysql_fetch_object($res)) {

 135      $item = new FeedItem();

 136      $item->title = $data->title;

 137      $item->link = $data->url;

 138      $item->description = $data->short;

 139  

 140      //optional

 141      item->descriptionTruncSize = 500;

 142      item->descriptionHtmlSyndicated = true;

 143  

 144      $item->date = $data->newsdate;

 145      $item->source = "http://www.dailyphp.net";

 146      $item->author = "John Doe";

 147  

 148      $rss->addItem($item);

 149  }

 150  

 151  // valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated),

 152  // MBOX, OPML, ATOM1.0, HTML, JS

 153  echo $rss->saveFeed("RSS1.0", "news/feed.xml");

 154  

 155  

 156  ***************************************************************************

 157  *          A little setup                                                 *

 158  **************************************************************************/
 159  
 160  // no direct access

 161  defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
 162  
 163  
 164  // your local timezone, set to "" to disable or for GMT

 165  define("TIME_ZONE","+01:00");
 166  
 167  
 168  
 169  /**

 170   * Version string.

 171   **/
 172  define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2");
 173  
 174  
 175  
 176  /**

 177   * A FeedItem is a part of a FeedCreator feed.

 178   *

 179   * @author Kai Blankenhorn <kaib@bitfolge.de>

 180   * @since 1.3

 181   */
 182  class FeedItem extends HtmlDescribable {
 183      /**

 184       * Mandatory attributes of an item.

 185       */
 186      var $title, $description, $link;
 187  
 188      /**

 189       * Optional attributes of an item.

 190       */
 191      var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator;
 192  
 193      /**

 194       * Publishing date of an item. May be in one of the following formats:

 195       *

 196       *    RFC 822:

 197       *    "Mon, 20 Jan 03 18:05:41 +0400"

 198       *    "20 Jan 03 18:05:41 +0000"

 199       *

 200       *    ISO 8601:

 201       *    "2003-01-20T18:05:41+04:00"

 202       *

 203       *    Unix:

 204       *    1043082341

 205       */
 206      var $date;
 207  
 208      /**

 209       * Any additional elements to include as an assiciated array. All $key => $value pairs

 210       * will be included unencoded in the feed item in the form

 211       *     <$key>$value</$key>

 212       * Again: No encoding will be used! This means you can invalidate or enhance the feed

 213       * if $value contains markup. This may be abused to embed tags not implemented by

 214       * the FeedCreator class used.

 215       */
 216      var $additionalElements = Array();
 217  
 218      // on hold

 219      // var $source;

 220  }
 221  
 222  
 223  
 224  /**

 225   * An FeedImage may be added to a FeedCreator feed.

 226   * @author Kai Blankenhorn <kaib@bitfolge.de>

 227   * @since 1.3

 228   */
 229  class FeedImage extends HtmlDescribable {
 230      /**

 231       * Mandatory attributes of an image.

 232       */
 233      var $title, $url, $link;
 234  
 235      /**

 236       * Optional attributes of an image.

 237       */
 238      var $width, $height, $description;
 239  }
 240  
 241  
 242  
 243  /**

 244   * An HtmlDescribable is an item within a feed that can have a description that may

 245   * include HTML markup.

 246   */
 247  class HtmlDescribable {
 248      /**

 249       * Indicates whether the description field should be rendered in HTML.

 250       */
 251      var $descriptionHtmlSyndicated;
 252  
 253      /**

 254       * Indicates whether and to how many characters a description should be truncated.

 255       */
 256      var $descriptionTruncSize;
 257  
 258      /**

 259       * Returns a formatted description field, depending on descriptionHtmlSyndicated and

 260       * $descriptionTruncSize properties

 261       * @return    string    the formatted description

 262       */
 263  	function getDescription() {
 264          $descriptionField = new FeedHtmlField($this->description);
 265          $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated;
 266          $descriptionField->truncSize = $this->descriptionTruncSize;
 267          return $descriptionField->output();
 268      }
 269  
 270  }
 271  
 272  
 273  /**

 274   * An FeedHtmlField describes and generates

 275   * a feed, item or image html field (probably a description). Output is

 276   * generated based on $truncSize, $syndicateHtml properties.

 277   * @author Pascal Van Hecke <feedcreator.class.php@vanhecke.info>

 278   * @version 1.6

 279   */
 280  class FeedHtmlField {
 281      /**

 282       * Mandatory attributes of a FeedHtmlField.

 283       */
 284      var $rawFieldContent;
 285  
 286      /**

 287       * Optional attributes of a FeedHtmlField.

 288       *

 289       */
 290      var $truncSize, $syndicateHtml;
 291  
 292      /**

 293       * Creates a new instance of FeedHtmlField.

 294       * @param  $string: if given, sets the rawFieldContent property

 295       */
 296  	function FeedHtmlField($parFieldContent) {
 297          if ($parFieldContent) {
 298              $this->rawFieldContent = $parFieldContent;
 299          }
 300      }
 301  
 302  
 303      /**

 304       * Creates the right output, depending on $truncSize, $syndicateHtml properties.

 305       * @return string    the formatted field

 306       */
 307  	function output() {
 308          // when field available and syndicated in html we assume

 309          // - valid html in $rawFieldContent and we enclose in CDATA tags

 310          // - no truncation (truncating risks producing invalid html)

 311          if (!$this->rawFieldContent) {
 312              $result = "";
 313          }    elseif ($this->syndicateHtml) {
 314              $result = "<![CDATA[".$this->rawFieldContent."]]>";
 315          } else {
 316              if ($this->truncSize and is_int($this->truncSize)) {
 317                  $result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize);
 318              } else {
 319                  $result = htmlspecialchars($this->rawFieldContent);
 320              }
 321          }
 322          return $result;
 323      }
 324  
 325  }
 326  
 327  
 328  
 329  /**

 330   * UniversalFeedCreator lets you choose during runtime which

 331   * format to build.

 332   * For general usage of a feed class, see the FeedCreator class

 333   * below or the example above.

 334   *

 335   * @since 1.3

 336   * @author Kai Blankenhorn <kaib@bitfolge.de>

 337   */
 338  class UniversalFeedCreator extends FeedCreator {
 339      var $_feed;
 340  
 341  	function _setFormat($format) {
 342          switch (strtoupper($format)) {
 343  
 344              case "2.0":
 345                  // fall through

 346              case "RSS2.0":
 347                  $this->_feed = new RSSCreator20();
 348                  break;
 349  
 350              case "1.0":
 351                  // fall through

 352              case "RSS1.0":
 353                  $this->_feed = new RSSCreator10();
 354                  break;
 355  
 356              case "0.91":
 357                  // fall through

 358              case "RSS0.91":
 359                  $this->_feed = new RSSCreator091();
 360                  break;
 361  
 362              case "PIE0.1":
 363                  $this->_feed = new PIECreator01();
 364                  break;
 365  
 366              case "MBOX":
 367                  $this->_feed = new MBOXCreator();
 368                  break;
 369  
 370              case "OPML":
 371                  $this->_feed = new OPMLCreator();
 372                  break;
 373  
 374              case "ATOM":
 375                  // fall through

 376  
 377              case "ATOM1.0":
 378                  $this->_feed = new AtomCreator10();
 379                  break;
 380  
 381              case "HTML":
 382                  $this->_feed = new HTMLCreator();
 383                  break;
 384  
 385              case "JS":
 386                  // fall through

 387              case "JAVASCRIPT":
 388                  $this->_feed = new JSCreator();
 389                  break;
 390  
 391              default:
 392                  $this->_feed = new RSSCreator091();
 393                  break;
 394          }
 395  
 396          $vars = get_object_vars($this);
 397          foreach ($vars as $key => $value) {
 398              // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself

 399              if (!in_array($key, array("_feed", "contentType", "encoding"))) {
 400                  $this->_feed->{$key} = $this->{$key};
 401              }
 402          }
 403      }
 404  
 405      /**

 406       * Creates a syndication feed based on the items previously added.

 407       *

 408       * @see        FeedCreator::addItem()

 409       * @param    string    format    format the feed should comply to. Valid values are:

 410       *            "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM1.0", "HTML", "JS"

 411       * @return    string    the contents of the feed.

 412       */
 413  	function createFeed($format = "RSS0.91") {
 414          $this->_setFormat($format);
 415          return $this->_feed->createFeed();
 416      }
 417  
 418  
 419  
 420      /**

 421       * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect

 422       * header may be sent to redirect the use to the newly created file.

 423       * @since 1.4

 424       *

 425       * @param    string    format    format the feed should comply to. Valid values are:

 426       *            "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM1.0", "HTML", "JS"

 427       * @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()).

 428       * @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.

 429       */
 430  	function saveFeed($format="RSS0.91", $filename="", $displayContents=true) {
 431          $this->_setFormat($format);
 432          $this->_feed->saveFeed($filename, $displayContents);
 433      }
 434  
 435  
 436     /**

 437      * Turns on caching and checks if there is a recent version of this feed in the cache.

 438      * If there is, an HTTP redirect header is sent.

 439      * To effectively use caching, you should create the FeedCreator object and call this method

 440      * before anything else, especially before you do the time consuming task to build the feed

 441      * (web fetching, for example).

 442      *

 443      * @param   string   format   format the feed should comply to. Valid values are:

 444      *       "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM1.0".

 445      * @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()).

 446      * @param timeout int      optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)

 447      */
 448     function useCached($format="RSS0.91", $filename="", $timeout=3600) {
 449        $this->_setFormat($format);
 450        $this->_feed->useCached($filename, $timeout);
 451     }
 452  
 453  }
 454  
 455  
 456  /**

 457   * FeedCreator is the abstract base implementation for concrete

 458   * implementations that implement a specific format of syndication.

 459   *

 460   * @abstract

 461   * @author Kai Blankenhorn <kaib@bitfolge.de>

 462   * @since 1.4

 463   */
 464  class FeedCreator extends HtmlDescribable {
 465  
 466      /**

 467       * Mandatory attributes of a feed.

 468       */
 469      var $title, $description, $link;
 470  
 471  
 472      /**

 473       * Optional attributes of a feed.

 474       */
 475      var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays;
 476  
 477      /**

 478      * The url of the external xsl stylesheet used to format the naked rss feed.

 479      * Ignored in the output when empty.

 480      */
 481      var $xslStyleSheet = "";
 482  
 483  
 484      /**

 485       * @access private

 486       */
 487      var $items = Array();
 488  
 489  
 490      /**

 491       * This feed's MIME content type.

 492       * @since 1.4

 493       * @access private

 494       */
 495      var $contentType = "application/xml";
 496  
 497  
 498      /**

 499       * This feed's character encoding.

 500       * @since 1.6.1

 501       **/
 502      var $encoding = "utf-8";
 503  
 504  
 505      /**

 506       * Any additional elements to include as an assiciated array. All $key => $value pairs

 507       * will be included unencoded in the feed in the form

 508       *     <$key>$value</$key>

 509       * Again: No encoding will be used! This means you can invalidate or enhance the feed

 510       * if $value contains markup. This may be abused to embed tags not implemented by

 511       * the FeedCreator class used.

 512       */
 513      var $additionalElements = Array();
 514  
 515  
 516      /**

 517       * Adds an FeedItem to the feed.

 518       *

 519       * @param object FeedItem $item The FeedItem to add to the feed.

 520       * @access public

 521       */
 522  	function addItem($item) {
 523          $this->items[] = $item;
 524      }
 525  
 526  
 527      /**

 528       * Truncates a string to a certain length at the most sensible point.

 529       * First, if there's a '.' character near the end of the string, the string is truncated after this character.

 530       * If there is no '.', the string is truncated after the last ' ' character.

 531       * If the string is truncated, " ..." is appended.

 532       * If the string is already shorter than $length, it is returned unchanged.

 533       *

 534       * @static

 535       * @param string    string A string to be truncated.

 536       * @param int        length the maximum length the string should be truncated to

 537       * @return string    the truncated string

 538       */
 539  	function iTrunc($string, $length) {
 540          if (strlen($string)<=$length) {
 541              return $string;
 542          }
 543  
 544          $pos = strrpos($string,".");
 545          if ($pos>=$length-4) {
 546              $string = substr($string,0,$length-4);
 547              $pos = strrpos($string,".");
 548          }
 549          if ($pos>=$length*0.4) {
 550              return substr($string,0,$pos+1)." ...";
 551          }
 552  
 553          $pos = strrpos($string," ");
 554          if ($pos>=$length-4) {
 555              $string = substr($string,0,$length-4);
 556              $pos = strrpos($string," ");
 557          }
 558          if ($pos>=$length*0.4) {
 559              return substr($string,0,$pos)." ...";
 560          }
 561  
 562          return substr($string,0,$length-4)." ...";
 563  
 564      }
 565  
 566  
 567      /**

 568       * Creates a comment indicating the generator of this feed.

 569       * The format of this comment seems to be recognized by

 570       * Syndic8.com.

 571       */
 572  	function _createGeneratorComment() {
 573          return "<!-- generator=\"".FEEDCREATOR_VERSION."\" -->\n";
 574      }
 575  
 576  
 577      /**

 578       * Creates a string containing all additional elements specified in

 579       * $additionalElements.

 580       * @param    elements    array    an associative array containing key => value pairs

 581       * @param indentString    string    a string that will be inserted before every generated line

 582       * @return    string    the XML tags corresponding to $additionalElements

 583       */
 584  	function _createAdditionalElements($elements, $indentString="") {
 585          $ae = "";
 586          if (is_array($elements)) {
 587              foreach($elements AS $key => $value) {
 588                  $ae.= $indentString."<$key>$value</$key>\n";
 589              }
 590          }
 591          return $ae;
 592      }
 593  
 594  	function _createStylesheetReferences() {
 595          $xml = "";
 596          if ($this->cssStyleSheet) $xml .= "<?xml-stylesheet href=\"".$this->cssStyleSheet."\" type=\"text/css\"?>\n";
 597          if ($this->xslStyleSheet) $xml .= "<?xml-stylesheet href=\"".$this->xslStyleSheet."\" type=\"text/xsl\"?>\n";
 598          return $xml;
 599      }
 600  
 601  
 602      /**

 603       * Builds the feed's text.

 604       * @abstract

 605       * @return    string    the feed's complete text

 606       */
 607  	function createFeed() {
 608      }
 609  
 610      /**

 611       * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml.

 612       * For example:

 613       *

 614       * echo $_SERVER["PHP_SELF"]."\n";

 615       * echo FeedCreator::_generateFilename();

 616       *

 617       * would produce:

 618       *

 619       * /rss/latestnews.php

 620       * latestnews.xml

 621       *

 622       * @return string the feed cache filename

 623       * @since 1.4

 624       * @access private

 625       */
 626  	function _generateFilename() {
 627          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
 628          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml";
 629      }
 630  
 631  
 632      /**

 633       * @since 1.4

 634       * @access private

 635       */
 636  	function _redirect($filename) {
 637          // attention, heavily-commented-out-area

 638  
 639          // maybe use this in addition to file time checking

 640          //Header("Expires: ".date("r",time()+$this->_timeout));

 641  
 642          /* no caching at all, doesn't seem to work as good:

 643          Header("Cache-Control: no-cache");

 644          Header("Pragma: no-cache");

 645          */
 646  
 647          // HTTP redirect, some feed readers' simple HTTP implementations don't follow it

 648          //Header("Location: ".$filename);

 649  
 650          //Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename));

 651          Header("Content-Type: ".$this->contentType."; charset=".$this->encoding);
 652          Header("Content-Disposition: inline; filename=".basename($filename));
 653          readfile($filename, "r");
 654          die();
 655      }
 656  
 657      /**

 658       * Turns on caching and checks if there is a recent version of this feed in the cache.

 659       * If there is, an HTTP redirect header is sent.

 660       * To effectively use caching, you should create the FeedCreator object and call this method

 661       * before anything else, especially before you do the time consuming task to build the feed

 662       * (web fetching, for example).

 663       * @since 1.4

 664       * @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()).

 665       * @param timeout    int        optional    the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)

 666       */
 667  	function useCached($filename="", $timeout=3600) {
 668          $this->_timeout = $timeout;
 669          if ($filename=="") {
 670              $filename = $this->_generateFilename();
 671          }
 672          if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) {
 673              $this->_redirect($filename);
 674          }
 675      }
 676  
 677  
 678      /**

 679       * Saves this feed as a file on the local disk. After the file is saved, a redirect

 680       * header may be sent to redirect the user to the newly created file.

 681       * @since 1.4

 682       *

 683       * @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()).

 684       * @param redirect    boolean    optional    send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file.

 685       */
 686  	function saveFeed($filename="", $displayContents=true) {
 687          if ($filename=="") {
 688              $filename = $this->_generateFilename();
 689          }
 690          $feedFile = fopen($filename, "w+");
 691          if ($feedFile) {
 692              fputs($feedFile,$this->createFeed());
 693              fclose($feedFile);
 694              if ($displayContents) {
 695                  $this->_redirect($filename);
 696              }
 697          } else {
 698              echo "<br /><strong>Error creating feed file, please check write permissions.</strong><br />";
 699          }
 700      }
 701  
 702  }
 703  
 704  
 705  /**

 706   * FeedDate is an internal class that stores a date for a feed or feed item.

 707   * Usually, you won't need to use this.

 708   */
 709  class FeedDate {
 710      var $unix;
 711  
 712      /**

 713       * Creates a new instance of FeedDate representing a given date.

 714       * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps.

 715       * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used.

 716       */
 717  	function FeedDate($dateString="") {
 718          if ($dateString=="") $dateString = date("r");
 719  
 720          if (is_integer($dateString)) {
 721              $this->unix = $dateString;
 722              return;
 723          }
 724          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)) {
 725              $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);
 726              $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]);
 727              if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
 728                  $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
 729              } else {
 730                  if (strlen($matches[7])==1) {
 731                      $oneHour = 3600;
 732                      $ord = ord($matches[7]);
 733                      if ($ord < ord("M")) {
 734                          $tzOffset = (ord("A") - $ord - 1) * $oneHour;
 735                      } elseif ($ord >= ord("M") AND $matches[7]!="Z") {
 736                          $tzOffset = ($ord - ord("M")) * $oneHour;
 737                      } elseif ($matches[7]=="Z") {
 738                          $tzOffset = 0;
 739                      }
 740                  }
 741                  switch ($matches[7]) {
 742                      case "UT":
 743                      case "GMT":    $tzOffset = 0;
 744                  }
 745              }
 746              $this->unix += $tzOffset;
 747              return;
 748          }
 749          if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) {
 750              $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]);
 751              if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
 752                  $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
 753              } else {
 754                  if ($matches[7]=="Z") {
 755                      $tzOffset = 0;
 756                  }
 757              }
 758              $this->unix += $tzOffset;
 759              return;
 760          }
 761          $this->unix = 0;
 762      }
 763  
 764      /**

 765       * Gets the date stored in this FeedDate as an RFC 822 date.

 766       *

 767       * @return a date in RFC 822 format

 768       */
 769  	function rfc822() {
 770          //return gmdate("r",$this->unix);

 771          $date = gmdate("D, d M Y H:i:s", $this->unix);
 772          if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE);
 773          return $date;
 774      }
 775  
 776      /**

 777       * Gets the date stored in this FeedDate as an ISO 8601 date.

 778       *

 779       * @return a date in ISO 8601 format

 780       */
 781  	function iso8601() {
 782          $date = gmdate("Y-m-d\TH:i:sO",$this->unix);
 783          $date = substr($date,0,22) . ':' . substr($date,-2);
 784          if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date);
 785          return $date;
 786      }
 787  
 788      /**

 789       * Gets the date stored in this FeedDate as unix time stamp.

 790       *

 791       * @return a date as a unix time stamp

 792       */
 793  	function unix() {
 794          return $this->unix;
 795      }
 796  }
 797  
 798  
 799  /**

 800   * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0.

 801   *

 802   * @see http://www.purl.org/rss/1.0/

 803   * @since 1.3

 804   * @author Kai Blankenhorn <kaib@bitfolge.de>

 805   */
 806  class RSSCreator10 extends FeedCreator {
 807  
 808      /**

 809       * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.

 810       * The feed will contain all items previously added in the same order.

 811       * @return    string    the feed's complete text

 812       */
 813  	function createFeed() {
 814          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
 815          $feed.= $this->_createGeneratorComment();
 816          if ($this->cssStyleSheet=="") {
 817              $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css";
 818          }
 819          $feed.= $this->_createStylesheetReferences();
 820          $feed.= "<rdf:RDF\n";
 821          $feed.= "    xmlns=\"http://purl.org/rss/1.0/\"\n";
 822          $feed.= "    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n";
 823          $feed.= "    xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n";
 824          $feed.= "    xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
 825          $feed.= "    <channel rdf:about=\"".$this->syndicationURL."\">\n";
 826          $feed.= "        <title>".htmlspecialchars($this->title)."</title>\n";
 827          $feed.= "        <description>".htmlspecialchars($this->description)."</description>\n";
 828          $feed.= "        <link>".$this->link."</link>\n";
 829          if ($this->image!=null) {
 830              $feed.= "        <image rdf:resource=\"".$this->image->url."\" />\n";
 831          }
 832          $now = new FeedDate();
 833          $feed.= "       <dc:date>".htmlspecialchars($now->iso8601())."</dc:date>\n";
 834          $feed.= "        <items>\n";
 835          $feed.= "            <rdf:Seq>\n";
 836          for ($i=0;$i<count($this->items);$i++) {
 837              $feed.= "                <rdf:li rdf:resource=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
 838          }
 839          $feed.= "            </rdf:Seq>\n";
 840          $feed.= "        </items>\n";
 841          $feed.= "    </channel>\n";
 842          if ($this->image!=null) {
 843              $feed.= "    <image rdf:about=\"".$this->image->url."\">\n";
 844              $feed.= "        <title>".$this->image->title."</title>\n";
 845              $feed.= "        <link>".$this->image->link."</link>\n";
 846              $feed.= "        <url>".$this->image->url."</url>\n";
 847              $feed.= "    </image>\n";
 848          }
 849          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
 850  
 851          for ($i=0;$i<count($this->items);$i++) {
 852              $feed.= "    <item rdf:about=\"".htmlspecialchars($this->items[$i]->link)."\">\n";
 853              //$feed.= "        <dc:type>Posting</dc:type>\n";

 854              $feed.= "        <dc:format>text/html</dc:format>\n";
 855              if ($this->items[$i]->date!=null) {
 856                  $itemDate = new FeedDate($this->items[$i]->date);
 857                  $feed.= "        <dc:date>".htmlspecialchars($itemDate->iso8601())."</dc:date>\n";
 858              }
 859              if ($this->items[$i]->source!="") {
 860                  $feed.= "        <dc:source>".htmlspecialchars($this->items[$i]->source)."</dc:source>\n";
 861              }
 862              if ($this->items[$i]->author!="") {
 863                  $feed.= "        <dc:creator>".htmlspecialchars($this->items[$i]->author)."</dc:creator>\n";
 864              }
 865              $feed.= "        <title>".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")))."</title>\n";
 866              $feed.= "        <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
 867              $feed.= "        <description>".htmlspecialchars($this->items[$i]->description)."</description>\n";
 868              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
 869              $feed.= "    </item>\n";
 870          }
 871          $feed.= "</rdf:RDF>\n";
 872          return $feed;
 873      }
 874  }
 875  
 876  
 877  
 878  /**

 879   * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3.

 880   *

 881   * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html

 882   * @since 1.3

 883   * @author Kai Blankenhorn <kaib@bitfolge.de>

 884   */
 885  class RSSCreator091 extends FeedCreator {
 886  
 887      /**

 888       * Stores this RSS feed's version number.

 889       * @access private

 890       */
 891      var $RSSVersion;
 892  
 893  	function RSSCreator091() {
 894          $this->_setRSSVersion("0.91");
 895          $this->contentType = "application/rss+xml";
 896      }
 897  
 898      /**

 899       * Sets this RSS feed's version number.

 900       * @access private

 901       */
 902  	function _setRSSVersion($version) {
 903          $this->RSSVersion = $version;
 904      }
 905  
 906      /**

 907       * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.

 908       * The feed will contain all items previously added in the same order.

 909       * @return    string    the feed's complete text

 910       */
 911  	function createFeed() {
 912          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
 913          $feed.= $this->_createGeneratorComment();
 914          $feed.= $this->_createStylesheetReferences();
 915          $feed.= "<rss version=\"".$this->RSSVersion."\">\n";
 916          $feed.= "    <channel>\n";
 917          $feed.= "        <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
 918          $this->descriptionTruncSize = 500;
 919          $feed.= "        <description>".$this->getDescription()."</description>\n";
 920          $feed.= "        <link>".$this->link."</link>\n";
 921          $now = new FeedDate();
 922          $feed.= "        <lastBuildDate>".htmlspecialchars($now->rfc822())."</lastBuildDate>\n";
 923          $feed.= "        <generator>".FEEDCREATOR_VERSION."</generator>\n";
 924  
 925          if ($this->image!=null) {
 926              $feed.= "        <image>\n";
 927              $feed.= "            <url>".$this->image->url."</url>\n";
 928              $feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."</title>\n";
 929              $feed.= "            <link>".$this->image->link."</link>\n";
 930              if ($this->image->width!="") {
 931                  $feed.= "            <width>".$this->image->width."</width>\n";
 932              }
 933              if ($this->image->height!="") {
 934                  $feed.= "            <height>".$this->image->height."</height>\n";
 935              }
 936              if ($this->image->description!="") {
 937                  $feed.= "            <description>".$this->image->getDescription()."</description>\n";
 938              }
 939              $feed.= "        </image>\n";
 940          }
 941          if ($this->language!="") {
 942              $feed.= "        <language>".$this->language."</language>\n";
 943          }
 944          if ($this->copyright!="") {
 945              $feed.= "        <copyright>".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."</copyright>\n";
 946          }
 947          if ($this->editor!="") {
 948              $feed.= "        <managingEditor>".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."</managingEditor>\n";
 949          }
 950          if ($this->webmaster!="") {
 951              $feed.= "        <webMaster>".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."</webMaster>\n";
 952          }
 953          if ($this->pubDate!="") {
 954              $pubDate = new FeedDate($this->pubDate);
 955              $feed.= "        <pubDate>".htmlspecialchars($pubDate->rfc822())."</pubDate>\n";
 956          }
 957          if ($this->category!="") {
 958              $feed.= "        <category>".htmlspecialchars($this->category)."</category>\n";
 959          }
 960          if ($this->docs!="") {
 961              $feed.= "        <docs>".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."</docs>\n";
 962          }
 963          if ($this->ttl!="") {
 964              $feed.= "        <ttl>".htmlspecialchars($this->ttl)."</ttl>\n";
 965          }
 966          if ($this->rating!="") {
 967              $feed.= "        <rating>".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."</rating>\n";
 968          }
 969          if ($this->skipHours!="") {
 970              $feed.= "        <skipHours>".htmlspecialchars($this->skipHours)."</skipHours>\n";
 971          }
 972          if ($this->skipDays!="") {
 973              $feed.= "        <skipDays>".htmlspecialchars($this->skipDays)."</skipDays>\n";
 974          }
 975          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
 976  
 977          for ($i=0;$i<count($this->items);$i++) {
 978              $feed.= "        <item>\n";
 979              $feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
 980              $feed.= "            <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
 981              $feed.= "            <description>".$this->items[$i]->getDescription()."</description>\n";
 982  
 983              if ($this->items[$i]->author!="") {
 984                  $feed.= "            <author>".htmlspecialchars($this->items[$i]->author)."</author>\n";
 985              }
 986              /*

 987              // on hold

 988              if ($this->items[$i]->source!="") {

 989                      $feed.= "            <source>".htmlspecialchars($this->items[$i]->source)."</source>\n";

 990              }

 991              */
 992              if ($this->items[$i]->category!="") {
 993                  $feed.= "            <category>".htmlspecialchars($this->items[$i]->category)."</category>\n";
 994              }
 995              if ($this->items[$i]->comments!="") {
 996                  $feed.= "            <comments>".htmlspecialchars($this->items[$i]->comments)."</comments>\n";
 997              }
 998              if ($this->items[$i]->date!="") {
 999              $itemDate = new FeedDate($this->items[$i]->date);
1000                  $feed.= "            <pubDate>".htmlspecialchars($itemDate->rfc822())."</pubDate>\n";
1001              }
1002              if ($this->items[$i]->guid!="") {
1003                  $feed.= "            <guid>".htmlspecialchars($this->items[$i]->guid)."</guid>\n";
1004              }
1005              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1006              $feed.= "        </item>\n";
1007          }
1008          $feed.= "    </channel>\n";
1009          $feed.= "</rss>\n";
1010          return $feed;
1011      }
1012  }
1013  
1014  
1015  
1016  /**

1017   * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0.

1018   *

1019   * @see http://backend.userland.com/rss

1020   * @since 1.3

1021   * @author Kai Blankenhorn <kaib@bitfolge.de>

1022   */
1023  class RSSCreator20 extends RSSCreator091 {
1024  
1025      function RSSCreator20() {
1026          parent::_setRSSVersion("2.0");
1027      }
1028  
1029  }
1030  
1031  
1032  /**

1033   * PIECreator01 is a FeedCreator that implements the emerging PIE specification,

1034   * as in http://intertwingly.net/wiki/pie/Syntax.

1035   *

1036   * @deprecated

1037   * @since 1.3

1038   * @author Scott Reynen <scott@randomchaos.com> and Kai Blankenhorn <kaib@bitfolge.de>

1039   */
1040  class PIECreator01 extends FeedCreator {
1041  
1042  	function PIECreator01() {
1043          $this->encoding = "utf-8";
1044      }
1045  
1046  	function createFeed() {
1047          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1048          $feed.= $this->_createStylesheetReferences();
1049          $feed.= "<feed version=\"0.1\" xmlns=\"http://example.com/newformat#\">\n";
1050          $feed.= "    <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
1051          $this->truncSize = 500;
1052          $feed.= "    <subtitle>".$this->getDescription()."</subtitle>\n";
1053          $feed.= "    <link>".$this->link."</link>\n";
1054          for ($i=0;$i<count($this->items);$i++) {
1055              $feed.= "    <entry>\n";
1056              $feed.= "        <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
1057              $feed.= "        <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
1058              $itemDate = new FeedDate($this->items[$i]->date);
1059              $feed.= "        <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1060              $feed.= "        <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1061              $feed.= "        <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1062              $feed.= "        <id>".htmlspecialchars($this->items[$i]->guid)."</id>\n";
1063              if ($this->items[$i]->author!="") {
1064                  $feed.= "        <author>\n";
1065                  $feed.= "            <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1066                  if ($this->items[$i]->authorEmail!="") {
1067                      $feed.= "            <email>".$this->items[$i]->authorEmail."</email>\n";
1068                  }
1069                  $feed.="        </author>\n";
1070              }
1071              $feed.= "        <content type=\"text/html\" xml:lang=\"en-us\">\n";
1072              $feed.= "            <div xmlns=\"http://www.w3.org/1999/xhtml\">".$this->items[$i]->getDescription()."</div>\n";
1073              $feed.= "        </content>\n";
1074              $feed.= "    </entry>\n";
1075          }
1076          $feed.= "</feed>\n";
1077          return $feed;
1078      }
1079  }
1080  
1081  
1082  /**

1083   * DEPRICATED

1084   *

1085   *

1086   * AtomCreator03 is a FeedCreator that implements the atom specification,

1087   * as in http://www.intertwingly.net/wiki/pie/FrontPage.

1088   * Please note that just by using AtomCreator03 you won't automatically

1089   * produce valid atom files. For example, you have to specify either an editor

1090   * for the feed or an author for every single feed item.

1091   *

1092   * Some elements have not been implemented yet. These are (incomplete list):

1093   * author URL, item author's email and URL, item contents, alternate links,

1094   * other link content types than text/html. Some of them may be created with

1095   * AtomCreator03::additionalElements.

1096   *

1097   * @see FeedCreator#additionalElements

1098   * @since 1.6

1099   * @author Kai Blankenhorn <kaib@bitfolge.de>, Scott Reynen <scott@randomchaos.com>

1100   */
1101  class AtomCreator03 extends FeedCreator {
1102  
1103  	function AtomCreator03() {
1104          $this->contentType = "application/atom+xml";
1105          $this->encoding = "utf-8";
1106      }
1107  
1108  	function createFeed() {
1109          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1110          $feed.= $this->_createGeneratorComment();
1111          $feed.= $this->_createStylesheetReferences();
1112          $feed.= "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\"";
1113          if ($this->language!="") {
1114              $feed.= " xml:lang=\"".$this->language."\"";
1115          }
1116          $feed.= ">\n";
1117          $feed.= "    <title>".htmlspecialchars($this->title)."</title>\n";
1118          $feed.= "    <tagline>".htmlspecialchars($this->description)."</tagline>\n";
1119          $feed.= "    <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link)."\"/>\n";
1120          $feed.= "    <id>".htmlspecialchars($this->link)."</id>\n";
1121          $now = new FeedDate();
1122          $feed.= "    <modified>".htmlspecialchars($now->iso8601())."</modified>\n";
1123          if ($this->editor!="") {
1124              $feed.= "    <author>\n";
1125              $feed.= "        <name>".$this->editor."</name>\n";
1126              if ($this->editorEmail!="") {
1127                  $feed.= "        <email>".$this->editorEmail."</email>\n";
1128              }
1129              $feed.= "    </author>\n";
1130          }
1131          $feed.= "    <generator>".FEEDCREATOR_VERSION."</generator>\n";
1132          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
1133          for ($i=0;$i<count($this->items);$i++) {
1134              $feed.= "    <entry>\n";
1135              $feed.= "        <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n";
1136              $feed.= "        <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
1137              if ($this->items[$i]->date=="") {
1138                  $this->items[$i]->date = time();
1139              }
1140              $itemDate = new FeedDate($this->items[$i]->date);
1141              $feed.= "        <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1142              $feed.= "        <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1143              $feed.= "        <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1144              $feed.= "        <id>".htmlspecialchars($this->items[$i]->link)."</id>\n";
1145              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1146              if ($this->items[$i]->author!="") {
1147                  $feed.= "        <author>\n";
1148                  $feed.= "            <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1149                  $feed.= "        </author>\n";
1150              }
1151              if ($this->items[$i]->description!="") {
1152                  $feed.= "        <summary>".htmlspecialchars($this->items[$i]->description)."</summary>\n";
1153              }
1154              $feed.= "    </entry>\n";
1155          }
1156          $feed.= "</feed>\n";
1157          return $feed;
1158      }
1159  }
1160  
1161  /**

1162   * AtomCreator10 is a FeedCreator that implements the atom specification,

1163   * as in http://www.atomenabled.org/

1164   * @author neil.thompson <nthompson@mambo-foundation.org>

1165   */
1166  class AtomCreator10 extends FeedCreator {
1167  
1168  	function AtomCreator10() {
1169          $this->contentType = "application/atom+xml";
1170          $this->encoding = "utf-8";
1171      }
1172  
1173  	function createFeed() {
1174  
1175          $now = new FeedDate();
1176  
1177          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1178          $feed.= $this->_createGeneratorComment();
1179          $feed.= $this->_createStylesheetReferences();
1180          $feed.= "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n";
1181          $feed.= "    <title type=\"text\">".htmlspecialchars($this->title)."</title>\n";
1182          $feed.= "    <subtitle>".htmlspecialchars($this->description)."</subtitle>\n";
1183          $feed.= "    <link rel=\"alternate\" type=\"text/html\" hreflang=\"en\" href=\"".htmlspecialchars($this->link)."\"/>\n";
1184          $feed.= "    <link rel=\"self\" type=\"application/atom+xml\"  hreflang=\"en\" href=\"".htmlspecialchars($this->link)."/index2.php?option=com_rss&amp;feed=ATOM1.0&amp;no_html=1\"/>\n";
1185          $feed.= "    <id>".htmlspecialchars($this->link)."/</id>\n";
1186          $feed.= "    <updated>".htmlspecialchars($now->iso8601())."</updated>\n";
1187  
1188          if ($this->editor!="") {
1189              $feed.= "    <rights>".$this->editor;
1190              if ($this->editorEmail!="") {
1191                  $feed.= $this->editorEmail;
1192              }
1193              $feed.= "    </rights>\n";
1194          }
1195  
1196          $feed.= "    <generator>".FEEDCREATOR_VERSION."</generator>\n";
1197  
1198          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
1199  
1200          for ($i=0;$i<count($this->items);$i++) {
1201  
1202              $this->items[$i]->created = time();
1203              $itemDate = new FeedDate($this->items[$i]->created);
1204  
1205              $feed.= "    <entry>\n";
1206              $feed.= "        <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n";
1207        $feed.= "        <link rel=\"self\" type=\"application/atom+xml\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
1208              $feed.= "        <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
1209              $feed.= "        <updated>".htmlspecialchars($itemDate->iso8601())."</updated>\n";
1210              $feed.= "        <id>".htmlspecialchars($this->items[$i]->link)."</id>\n";
1211              $feed.= "        <author>\n";
1212        if ($this->items[$i]->author!="") {
1213                  $feed.= "        <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1214              }else{
1215          $feed.= "       <name>".htmlspecialchars($this->link)."</name>\n";
1216        }
1217        $feed.= "        </author>\n";
1218  
1219              if ($this->items[$i]->description!="") {
1220                  $feed.= "        <summary type=\"html\">".htmlspecialchars($this->items[$i]->description)."</summary>\n";
1221              }
1222              $feed.= "    </entry>\n";
1223  
1224          }
1225  
1226          $feed.= "</feed>\n";
1227          return $feed;
1228      }
1229  }
1230  
1231  
1232  /**

1233   * MBOXCreator is a FeedCreator that implements the mbox format

1234   * as described in http://www.qmail.org/man/man5/mbox.html

1235   *

1236   * @since 1.3

1237   * @author Kai Blankenhorn <kaib@bitfolge.de>

1238   */
1239  class MBOXCreator extends FeedCreator {
1240  
1241  	function MBOXCreator() {
1242          $this->contentType = "text/plain";
1243          $this->encoding = "ISO-8859-15";
1244      }
1245  
1246  	function qp_enc($input = "", $line_max = 76) {
1247          $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1248          $lines = preg_split("/(?:\r\n|\r|\n)/", $input);
1249          $eol = "\r\n";
1250          $escape = "=";
1251          $output = "";
1252          while( list(, $line) = each($lines) ) {
1253              //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary

1254              $linlen = strlen($line);
1255              $newline = "";
1256              for($i = 0; $i < $linlen; $i++) {
1257                  $c = substr($line, $i, 1);
1258                  $dec = ord($c);
1259                  if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only
1260                      $c = "=20";
1261                  } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
1262                      $h2 = floor($dec/16); $h1 = floor($dec%16);
1263                      $c = $escape.$hex["$h2"].$hex["$h1"];
1264                  }
1265                  if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
1266                      $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay

1267                      $newline = "";
1268                  }
1269                  $newline .= $c;
1270              } // end of for

1271              $output .= $newline.$eol;
1272          }
1273          return trim($output);
1274      }
1275  
1276  
1277      /**

1278       * Builds the MBOX contents.

1279       * @return    string    the feed's complete text

1280       */
1281  	function createFeed() {
1282          for ($i=0;$i<count($this->items);$i++) {
1283              if ($this->items[$i]->author!="") {
1284                  $from = $this->items[$i]->author;
1285              } else {
1286                  $from = $this->title;
1287              }
1288              $itemDate = new FeedDate($this->items[$i]->date);
1289              $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n";
1290              $feed.= "Content-Type: text/plain;\n";
1291              $feed.= "    charset=\"".$this->encoding."\"\n";
1292              $feed.= "Content-Transfer-Encoding: quoted-printable\n";
1293              $feed.= "Content-Type: text/plain\n";
1294              $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n";
1295              $feed.= "Date: ".$itemDate->rfc822()."\n";
1296              $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n";
1297              $feed.= "\n";
1298              $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description));
1299              $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body);
1300              $feed.= "\n";
1301              $feed.= "\n";
1302          }
1303          return $feed;
1304      }
1305  
1306      /**

1307       * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types.

1308       * @return string the feed cache filename

1309       * @since 1.4

1310       * @access private

1311       */
1312  	function _generateFilename() {
1313          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1314          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox";
1315      }
1316  }
1317  
1318  
1319  /**

1320   * OPMLCreator is a FeedCreator that implements OPML 1.0.

1321   *

1322   * @see http://opml.scripting.com/spec

1323   * @author Dirk Clemens, Kai Blankenhorn

1324   * @since 1.5

1325   */
1326  class OPMLCreator extends FeedCreator {
1327  
1328  	function OPMLCreator() {
1329          $this->encoding = "utf-8";
1330      }
1331  
1332  	function createFeed() {
1333          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1334          $feed.= $this->_createGeneratorComment();
1335          $feed.= $this->_createStylesheetReferences();
1336          $feed.= "<opml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
1337          $feed.= "<head>    \n";
1338          $feed.= "        <title>".htmlspecialchars($this->title)."</title>\n";
1339          if ($this->pubDate!="") {
1340              $date = new FeedDate($this->pubDate);
1341              $feed.= "         <dateCreated>".$date->rfc822()."</dateCreated>\n";
1342          }
1343          if ($this->lastBuildDate!="") {
1344              $date = new FeedDate($this->lastBuildDate);
1345              $feed.= "         <dateModified>".$date->rfc822()."</dateModified>\n";
1346          }
1347          if ($this->editor!="") {
1348              $feed.= "         <ownerName>".$this->editor."</ownerName>\n";
1349          }
1350          if ($this->editorEmail!="") {
1351              $feed.= "         <ownerEmail>".$this->editorEmail."</ownerEmail>\n";
1352          }
1353          $feed.= "    </head>\n";
1354          $feed.= "    <body>\n";
1355          for ($i=0;$i<count($this->items);$i++) {
1356              $feed.= "    <outline type=\"rss\" ";
1357              $title = htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")));
1358              $feed.= " title=\"".$title."\"";
1359              $feed.= " text=\"".$title."\"";
1360              //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\"";

1361              $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\"";
1362              $feed.= "/>\n";
1363          }
1364          $feed.= "    </body>\n";
1365          $feed.= "</opml>\n";
1366          return $feed;
1367      }
1368  }
1369  
1370  
1371  
1372  /**

1373   * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific

1374   * location, overriding the createFeed method of the parent FeedCreator.

1375   * The HTML produced can be included over http by scripting languages, or serve

1376   * as the source for an IFrame.

1377   * All output by this class is embedded in <div></div> tags to enable formatting

1378   * using CSS.

1379   *

1380   * @author Pascal Van Hecke

1381   * @since 1.7

1382   */
1383  class HTMLCreator extends FeedCreator {
1384  
1385      var $contentType = "text/html";
1386  
1387      /**

1388       * Contains HTML to be output at the start of the feed's html representation.

1389       */
1390      var $header;
1391  
1392      /**

1393       * Contains HTML to be output at the end of the feed's html representation.

1394       */
1395      var $footer ;
1396  
1397      /**

1398       * Contains HTML to be output between entries. A separator is only used in

1399       * case of multiple entries.

1400       */
1401      var $separator;
1402  
1403      /**

1404       * Used to prefix the stylenames to make sure they are unique

1405       * and do not clash with stylenames on the users' page.

1406       */
1407      var $stylePrefix;
1408  
1409      /**

1410       * Determines whether the links open in a new window or not.

1411       */
1412      var $openInNewWindow = true;
1413  
1414      var $imageAlign ="right";
1415  
1416      /**

1417       * In case of very simple output you may want to get rid of the style tags,

1418       * hence this variable.  There's no equivalent on item level, but of course you can

1419       * add strings to it while iterating over the items ($this->stylelessOutput .= ...)

1420       * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored

1421       * in the function createFeed().

1422       */
1423      var $stylelessOutput ="";
1424  
1425      /**

1426       * Writes the HTML.

1427       * @return    string    the scripts's complete text

1428       */
1429  	function createFeed() {
1430          // if there is styleless output, use the content of this variable and ignore the rest

1431          if ($this->stylelessOutput!="") {
1432              return $this->stylelessOutput;
1433          }
1434  
1435          //if no stylePrefix is set, generate it yourself depending on the script name

1436          if ($this->stylePrefix=="") {
1437              $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_";
1438          }
1439  
1440          //set an openInNewWindow_token_to be inserted or not

1441          if ($this->openInNewWindow) {
1442              $targetInsert = " target='_blank'";
1443          }
1444  
1445          // use this array to put the lines in and implode later with "document.write" javascript

1446          $feedArray = array();
1447          if ($this->image!=null) {
1448              $imageStr = "<a href='".$this->image->link."'".$targetInsert.">".
1449                              "<img src='".$this->image->url."' border='0' alt='".
1450                              FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
1451                              "' align='".$this->imageAlign."' ";
1452              if ($this->image->width) {
1453                  $imageStr .=" width='".$this->image->width. "' ";
1454              }
1455              if ($this->image->height) {
1456                  $imageStr .=" height='".$this->image->height."' ";
1457              }
1458              $imageStr .="/></a>";
1459              $feedArray[] = $imageStr;
1460          }
1461  
1462          if ($this->title) {
1463              $feedArray[] = "<div class='".$this->stylePrefix."title'><a href='".$this->link."' ".$targetInsert." class='".$this->stylePrefix."title'>".
1464                  FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</a></div>";
1465          }
1466          if ($this->getDescription()) {
1467              $feedArray[] = "<div class='".$this->stylePrefix."description'>".
1468                  str_replace("</XMLCDATA>", "", str_replace("<![CDATA[", "", $this->getDescription())).
1469                  "</div>";
1470          }
1471  
1472          if ($this->header) {
1473              $feedArray[] = "<div class='".$this->stylePrefix."header'>".$this->header."</div>";
1474          }
1475  
1476          for ($i=0;$i<count($this->items);$i++) {
1477              if ($this->separator and $i > 0) {
1478                  $feedArray[] = "<div class='".$this->stylePrefix."separator'>".$this->separator."</div>";
1479              }
1480  
1481              if ($this->items[$i]->title) {
1482                  if ($this->items[$i]->link) {
1483                      $feedArray[] =
1484                          "<div class='".$this->stylePrefix."item_title'><a href='".$this->items[$i]->link."' class='".$this->stylePrefix.
1485                          "item_title'".$targetInsert.">".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
1486                          "</a></div>";
1487                  } else {
1488                      $feedArray[] =
1489                          "<div class='".$this->stylePrefix."item_title'>".
1490                          FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
1491                          "</div>";
1492                  }
1493              }
1494              if ($this->items[$i]->getDescription()) {
1495                  $feedArray[] =
1496                  "<div class='".$this->stylePrefix."item_description'>".
1497                      str_replace("]]>", "", str_replace("<![CDATA[", "", $this->items[$i]->getDescription())).
1498                      "</div>";
1499              }
1500          }
1501          if ($this->footer) {
1502              $feedArray[] = "<div class='".$this->stylePrefix."footer'>".$this->footer."</div>";
1503          }
1504  
1505          $feed= "".join($feedArray, "\r\n");
1506          return $feed;
1507      }
1508  
1509      /**

1510       * Overrrides parent to produce .html extensions

1511       *

1512       * @return string the feed cache filename

1513       * @since 1.4

1514       * @access private

1515       */
1516  	function _generateFilename() {
1517          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1518          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html";
1519      }
1520  }
1521  
1522  
1523  /**

1524   * JSCreator is a class that writes a js file to a specific

1525   * location, overriding the createFeed method of the parent HTMLCreator.

1526   *

1527   * @author Pascal Van Hecke

1528   */
1529  class JSCreator extends HTMLCreator {
1530      var $contentType = "text/javascript";
1531  
1532      /**

1533       * writes the javascript

1534       * @return    string    the scripts's complete text

1535       */
1536  	function createFeed()
1537      {
1538          $feed = parent::createFeed();
1539          $feedArray = explode("\n",$feed);
1540  
1541          $jsFeed = "";
1542          foreach ($feedArray as $value) {
1543              $jsFeed .= "document.write('".trim(addslashes($value))."');\n";
1544          }
1545          return $jsFeed;
1546      }
1547  
1548      /**

1549       * Overrrides parent to produce .js extensions

1550       *

1551       * @return string the feed cache filename

1552       * @since 1.4

1553       * @access private

1554       */
1555  	function _generateFilename() {
1556          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1557          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js";
1558      }
1559  
1560  }
1561  
1562  
1563  
1564  /*** TEST SCRIPT *********************************************************

1565  

1566  //include("feedcreator.class.php");

1567  

1568  $rss = new UniversalFeedCreator();

1569  $rss->useCached();

1570  $rss->title = "PHP news";

1571  $rss->description = "daily news from the PHP scripting world";

1572  

1573  //optional

1574  //$rss->descriptionTruncSize = 500;

1575  //$rss->descriptionHtmlSyndicated = true;

1576  //$rss->xslStyleSheet = "http://feedster.com/rss20.xsl";

1577  

1578  $rss->link = "http://www.dailyphp.net/news";

1579  $rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF;

1580  

1581  $image = new FeedImage();

1582  $image->title = "dailyphp.net logo";

1583  $image->url = "http://www.dailyphp.net/images/logo.gif";

1584  $image->link = "http://www.dailyphp.net";

1585  $image->description = "Feed provided by dailyphp.net. Click to visit.";

1586  

1587  //optional

1588  $image->descriptionTruncSize = 500;

1589  $image->descriptionHtmlSyndicated = true;

1590  

1591  $rss->image = $image;

1592  

1593  // get your news items from somewhere, e.g. your database:

1594  //mysql_select_db($dbHost, $dbUser, $dbPass);

1595  //$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");

1596  //while ($data = mysql_fetch_object($res)) {

1597      $item = new FeedItem();

1598      $item->title = "This is an the test title of an item";

1599      $item->link = "http://localhost/item/";

1600      $item->description = "<strong>description in </strong><br />HTML";

1601  

1602      //optional

1603      //item->descriptionTruncSize = 500;

1604      $item->descriptionHtmlSyndicated = true;

1605  

1606      $item->date = time();

1607      $item->source = "http://www.dailyphp.net";

1608      $item->author = "John Doe";

1609  

1610      $rss->addItem($item);

1611  //}

1612  

1613  // valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS

1614  echo $rss->saveFeed("RSS0.91", "feed.xml");

1615  

1616  

1617  

1618  ***************************************************************************/
1619  
1620  ?>