[ Index ]
 

Code source de Joomla 1.0.13

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/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  
  30  v1.7.2    Joomla! 1.0.8
  31  12-Feb-2005 Rey Gigataras
  32   - Fixed artf3438 : RSS Feed Created it not base on the same encoding of the content
  33  
  34  v1.7.2    Joomla! 1.0
  35  15-Sep-2005 Rey Gigataras
  36   ^ Added publish date to syndicated feeds output [credit: gharding]
  37   ^ Added RSS Enclosure support to feedcreator [credit: Joseph L. LeBlanc]
  38   ^ Added Google Sitemap support to feedcreator
  39  
  40  *********************************
  41  
  42  v1.7.2    10-11-04
  43      license changed to LGPL
  44  
  45  v1.7.1
  46      fixed a syntax bug
  47      fixed left over debug code
  48  
  49  v1.7    07-18-04
  50      added HTML and JavaScript feeds (configurable via CSS) (thanks to Pascal Van Hecke)
  51      added HTML descriptions for all feed formats (thanks to Pascal Van Hecke)
  52      added a switch to select an external stylesheet (thanks to Pascal Van Hecke)
  53      changed default content-type to application/xml
  54      added character encoding setting
  55      fixed numerous smaller bugs (thanks to S�ren Fuhrmann of golem.de)
  56      improved changing ATOM versions handling (thanks to August Trometer)
  57      improved the UniversalFeedCreator's useCached method (thanks to S�ren Fuhrmann of golem.de)
  58      added charset output in HTTP headers (thanks to S�ren Fuhrmann of golem.de)
  59      added Slashdot namespace to RSS 1.0 (thanks to S�ren Fuhrmann of golem.de)
  60  
  61  v1.6    05-10-04
  62      added stylesheet to RSS 1.0 feeds
  63      fixed generator comment (thanks Kevin L. Papendick and Tanguy Pruvot)
  64      fixed RFC822 date bug (thanks Tanguy Pruvot)
  65      added TimeZone customization for RFC8601 (thanks Tanguy Pruvot)
  66      fixed Content-type could be empty (thanks Tanguy Pruvot)
  67      fixed author/creator in RSS1.0 (thanks Tanguy Pruvot)
  68  
  69  v1.6 beta    02-28-04
  70      added Atom 0.3 support (not all features, though)
  71      improved OPML 1.0 support (hopefully - added more elements)
  72      added support for arbitrary additional elements (use with caution)
  73      code beautification :-)
  74      considered beta due to some internal changes
  75  
  76  v1.5.1    01-27-04
  77      fixed some RSS 1.0 glitches (thanks to St�phane Vanpoperynghe)
  78      fixed some inconsistencies between documentation and code (thanks to Timothy Martin)
  79  
  80  v1.5    01-06-04
  81      added support for OPML 1.0
  82      added more documentation
  83  
  84  v1.4    11-11-03
  85      optional feed saving and caching
  86      improved documentation
  87      minor improvements
  88  
  89  v1.3    10-02-03
  90      renamed to FeedCreator, as it not only creates RSS anymore
  91      added support for mbox
  92      tentative support for echo/necho/atom/pie/???
  93  
  94  v1.2    07-20-03
  95      intelligent auto-truncating of RSS 0.91 attributes
  96      don't create some attributes when they're not set
  97      documentation improved
  98      fixed a real and a possible bug with date conversions
  99      code cleanup
 100  
 101  v1.1    06-29-03
 102      added images to feeds
 103      now includes most RSS 0.91 attributes
 104      added RSS 2.0 feeds
 105  
 106  v1.0    06-24-03
 107      initial release
 108  
 109  
 110  
 111  ***************************************************************************/
 112  
 113  /*** GENERAL USAGE *********************************************************
 114  
 115  include("feedcreator.class.php");
 116  
 117  $rss = new UniversalFeedCreator();
 118  $rss->useCached(); // use cached version if age<1 hour
 119  $rss->title = "PHP news";
 120  $rss->description = "daily news from the PHP scripting world";
 121  
 122  //optional
 123  $rss->descriptionTruncSize = 500;
 124  $rss->descriptionHtmlSyndicated = true;
 125  
 126  $rss->link = "http://www.dailyphp.net/news";
 127  $rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"];
 128  
 129  $image = new FeedImage();
 130  $image->title = "dailyphp.net logo";
 131  $image->url = "http://www.dailyphp.net/images/logo.gif";
 132  $image->link = "http://www.dailyphp.net";
 133  $image->description = "Feed provided by dailyphp.net. Click to visit.";
 134  
 135  //optional
 136  $image->descriptionTruncSize = 500;
 137  $image->descriptionHtmlSyndicated = true;
 138  
 139  $rss->image = $image;
 140  
 141  // get your news items from somewhere, e.g. your database:
 142  mysql_select_db($dbHost, $dbUser, $dbPass);
 143  $res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");
 144  while ($data = mysql_fetch_object($res)) {
 145      $item = new FeedItem();
 146      $item->title = $data->title;
 147      $item->link = $data->url;
 148      $item->description = $data->short;
 149  
 150      //optional
 151      item->descriptionTruncSize = 500;
 152      item->descriptionHtmlSyndicated = true;
 153  
 154      $item->date = $data->newsdate;
 155      $item->source = "http://www.dailyphp.net";
 156      $item->author = "John Doe";
 157  
 158      $rss->addItem($item);
 159  }
 160  
 161  // valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated),
 162  // MBOX, OPML, ATOM, ATOM0.3, HTML, JS
 163  echo $rss->saveFeed("RSS1.0", "news/feed.xml");
 164  
 165  
 166  ***************************************************************************
 167  *          A little setup                                                 *
 168  **************************************************************************/
 169  
 170  // no direct access
 171  defined( '_VALID_MOS' ) or die( 'Restricted access' );
 172  
 173  
 174  // your local timezone, set to "" to disable or for GMT
 175  define("TIME_ZONE","+01:00");
 176  
 177  
 178  
 179  /**
 180   * Version string.
 181   **/
 182  define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2");
 183  
 184  
 185  
 186  /**
 187   * A FeedItem is a part of a FeedCreator feed.
 188   *
 189   * @author Kai Blankenhorn <kaib@bitfolge.de>
 190   * @since 1.3
 191   */
 192  class FeedItem extends HtmlDescribable {
 193      /**
 194       * Mandatory attributes of an item.
 195       */
 196      var $title, $description, $link;
 197  
 198      /**
 199       * Optional attributes of an item.
 200       */
 201      var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator;
 202  
 203      /**
 204       * Publishing date of an item. May be in one of the following formats:
 205       *
 206       *    RFC 822:
 207       *    "Mon, 20 Jan 03 18:05:41 +0400"
 208       *    "20 Jan 03 18:05:41 +0000"
 209       *
 210       *    ISO 8601:
 211       *    "2003-01-20T18:05:41+04:00"
 212       *
 213       *    Unix:
 214       *    1043082341
 215       */
 216      var $date;
 217  
 218      /**
 219       * Any additional elements to include as an assiciated array. All $key => $value pairs
 220       * will be included unencoded in the feed item in the form
 221       *     <$key>$value</$key>
 222       * Again: No encoding will be used! This means you can invalidate or enhance the feed
 223       * if $value contains markup. This may be abused to embed tags not implemented by
 224       * the FeedCreator class used.
 225       */
 226      var $additionalElements = Array();
 227  
 228  
 229      // Added by Joseph LeBlanc, contact@jlleblanc.com
 230  
 231      var $enclosures = Array();
 232  
 233  	function addEnclosure($url, $length = 0, $type)    {
 234          $this->enclosures[] = array("url" => $url, "length" => $length, "type" => $type);
 235      }
 236  
 237      // end add, Joseph LeBlanc
 238  
 239      // on hold
 240      // var $source;
 241  }
 242  
 243  
 244  
 245  /**
 246   * An FeedImage may be added to a FeedCreator feed.
 247   * @author Kai Blankenhorn <kaib@bitfolge.de>
 248   * @since 1.3
 249   */
 250  class FeedImage extends HtmlDescribable {
 251      /**
 252       * Mandatory attributes of an image.
 253       */
 254      var $title, $url, $link;
 255  
 256      /**
 257       * Optional attributes of an image.
 258       */
 259      var $width, $height, $description;
 260  }
 261  
 262  
 263  
 264  /**
 265   * An HtmlDescribable is an item within a feed that can have a description that may
 266   * include HTML markup.
 267   */
 268  class HtmlDescribable {
 269      /**
 270       * Indicates whether the description field should be rendered in HTML.
 271       */
 272      var $descriptionHtmlSyndicated;
 273  
 274      /**
 275       * Indicates whether and to how many characters a description should be truncated.
 276       */
 277      var $descriptionTruncSize;
 278  
 279      /**
 280       * Returns a formatted description field, depending on descriptionHtmlSyndicated and
 281       * $descriptionTruncSize properties
 282       * @return    string    the formatted description
 283       */
 284  	function getDescription() {
 285          $descriptionField = new FeedHtmlField($this->description);
 286          $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated;
 287          $descriptionField->truncSize = $this->descriptionTruncSize;
 288          return $descriptionField->output();
 289      }
 290  
 291  }
 292  
 293  
 294  /**
 295   * An FeedHtmlField describes and generates
 296   * a feed, item or image html field (probably a description). Output is
 297   * generated based on $truncSize, $syndicateHtml properties.
 298   * @author Pascal Van Hecke <feedcreator.class.php@vanhecke.info>
 299   * @version 1.6
 300   */
 301  class FeedHtmlField {
 302      /**
 303       * Mandatory attributes of a FeedHtmlField.
 304       */
 305      var $rawFieldContent;
 306  
 307      /**
 308       * Optional attributes of a FeedHtmlField.
 309       *
 310       */
 311      var $truncSize, $syndicateHtml;
 312  
 313      /**
 314       * Creates a new instance of FeedHtmlField.
 315       * @param  $string: if given, sets the rawFieldContent property
 316       */
 317  	function FeedHtmlField($parFieldContent) {
 318          if ($parFieldContent) {
 319              $this->rawFieldContent = $parFieldContent;
 320          }
 321      }
 322  
 323  
 324      /**
 325       * Creates the right output, depending on $truncSize, $syndicateHtml properties.
 326       * @return string    the formatted field
 327       */
 328  	function output() {
 329          // when field available and syndicated in html we assume
 330          // - valid html in $rawFieldContent and we enclose in CDATA tags
 331          // - no truncation (truncating risks producing invalid html)
 332          if (!$this->rawFieldContent) {
 333              $result = "";
 334          }    elseif ($this->syndicateHtml) {
 335              $result = "<![CDATA[".$this->rawFieldContent."]]>";
 336          } else {
 337              if ($this->truncSize and is_int($this->truncSize)) {
 338                  $result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize);
 339              } else {
 340                  $result = htmlspecialchars($this->rawFieldContent);
 341              }
 342          }
 343          return $result;
 344      }
 345  
 346  }
 347  
 348  
 349  
 350  /**
 351   * UniversalFeedCreator lets you choose during runtime which
 352   * format to build.
 353   * For general usage of a feed class, see the FeedCreator class
 354   * below or the example above.
 355   *
 356   * @since 1.3
 357   * @author Kai Blankenhorn <kaib@bitfolge.de>
 358   */
 359  class UniversalFeedCreator extends FeedCreator {
 360      var $_feed;
 361  
 362  	function _setFormat($format) {
 363          switch (strtoupper($format)) {
 364  
 365              case "2.0":
 366                  // fall through
 367              case "RSS2.0":
 368                  $this->_feed = new RSSCreator20();
 369                  break;
 370  
 371              case "1.0":
 372                  // fall through
 373              case "RSS1.0":
 374                  $this->_feed = new RSSCreator10();
 375                  break;
 376  
 377              case "0.91":
 378                  // fall through
 379              case "RSS0.91":
 380                  $this->_feed = new RSSCreator091();
 381                  break;
 382  
 383              case "PIE0.1":
 384                  $this->_feed = new PIECreator01();
 385                  break;
 386  
 387              case "MBOX":
 388                  $this->_feed = new MBOXCreator();
 389                  break;
 390  
 391              case "OPML":
 392                  $this->_feed = new OPMLCreator();
 393                  break;
 394  
 395              case "ATOM":
 396                  // fall through: always the latest ATOM version
 397  
 398              case "ATOM0.3":
 399                  $this->_feed = new AtomCreator03();
 400                  break;
 401  
 402              case "HTML":
 403                  $this->_feed = new HTMLCreator();
 404                  break;
 405  
 406              case "JS":
 407                  // fall through
 408              case "JAVASCRIPT":
 409                  $this->_feed = new JSCreator();
 410                  break;
 411  
 412              default:
 413                  $this->_feed = new RSSCreator091();
 414                  break;
 415          }
 416  
 417          $vars = get_object_vars($this);
 418          foreach ($vars as $key => $value) {
 419              // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself
 420              if (!in_array($key, array("_feed", "contentType"))) {
 421                  $this->_feed->{$key} = $this->{$key};
 422              }
 423          }
 424      }
 425  
 426      /**
 427       * Creates a syndication feed based on the items previously added.
 428       *
 429       * @see        FeedCreator::addItem()
 430       * @param    string    format    format the feed should comply to. Valid values are:
 431       *            "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS"
 432       * @return    string    the contents of the feed.
 433       */
 434  	function createFeed($format = "RSS0.91") {
 435          $this->_setFormat($format);
 436          return $this->_feed->createFeed();
 437      }
 438  
 439  
 440  
 441      /**
 442       * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect
 443       * header may be sent to redirect the use to the newly created file.
 444       * @since 1.4
 445       *
 446       * @param    string    format    format the feed should comply to. Valid values are:
 447       *            "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS"
 448       * @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()).
 449       * @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.
 450       */
 451  	function saveFeed($format="RSS0.91", $filename="", $displayContents=true) {
 452          $this->_setFormat($format);
 453          $this->_feed->saveFeed($filename, $displayContents);
 454      }
 455  
 456  
 457     /**
 458      * Turns on caching and checks if there is a recent version of this feed in the cache.
 459      * If there is, an HTTP redirect header is sent.
 460      * To effectively use caching, you should create the FeedCreator object and call this method
 461      * before anything else, especially before you do the time consuming task to build the feed
 462      * (web fetching, for example).
 463      *
 464      * @param   string   format   format the feed should comply to. Valid values are:
 465      *       "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3".
 466      * @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()).
 467      * @param timeout int      optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
 468      */
 469     function useCached($format="RSS0.91", $filename="", $timeout=3600) {
 470        $this->_setFormat($format);
 471        $this->_feed->useCached($filename, $timeout);
 472     }
 473  
 474  }
 475  
 476  
 477  /**
 478   * FeedCreator is the abstract base implementation for concrete
 479   * implementations that implement a specific format of syndication.
 480   *
 481   * @abstract
 482   * @author Kai Blankenhorn <kaib@bitfolge.de>
 483   * @since 1.4
 484   */
 485  class FeedCreator extends HtmlDescribable {
 486  
 487      /**
 488       * Mandatory attributes of a feed.
 489       */
 490      var $title, $description, $link;
 491  
 492  
 493      /**
 494       * Optional attributes of a feed.
 495       */
 496      var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays;
 497  
 498      /**
 499      * The url of the external xsl stylesheet used to format the naked rss feed.
 500      * Ignored in the output when empty.
 501      */
 502      var $xslStyleSheet = "";
 503  
 504  
 505      /**
 506       * @access private
 507       */
 508      var $items = Array();
 509  
 510  
 511      /**
 512       * This feed's MIME content type.
 513       * @since 1.4
 514       * @access private
 515       */
 516      var $contentType = "application/xml";
 517  
 518  
 519      /**
 520       * This feed's character encoding.
 521       * @since 1.6.1
 522       **/
 523      var $encoding = "ISO-8859-1";
 524  
 525  
 526      /**
 527       * Any additional elements to include as an assiciated array. All $key => $value pairs
 528       * will be included unencoded in the feed in the form
 529       *     <$key>$value</$key>
 530       * Again: No encoding will be used! This means you can invalidate or enhance the feed
 531       * if $value contains markup. This may be abused to embed tags not implemented by
 532       * the FeedCreator class used.
 533       */
 534      var $additionalElements = Array();
 535  
 536  
 537      /**
 538       * Adds an FeedItem to the feed.
 539       *
 540       * @param object FeedItem $item The FeedItem to add to the feed.
 541       * @access public
 542       */
 543  	function addItem($item) {
 544          $this->items[] = $item;
 545      }
 546  
 547  
 548      /**
 549       * Truncates a string to a certain length at the most sensible point.
 550       * First, if there's a '.' character near the end of the string, the string is truncated after this character.
 551       * If there is no '.', the string is truncated after the last ' ' character.
 552       * If the string is truncated, " ..." is appended.
 553       * If the string is already shorter than $length, it is returned unchanged.
 554       *
 555       * @static
 556       * @param string    string A string to be truncated.
 557       * @param int        length the maximum length the string should be truncated to
 558       * @return string    the truncated string
 559       */
 560  	function iTrunc($string, $length) {
 561          if (strlen($string)<=$length) {
 562              return $string;
 563          }
 564  
 565          $pos = strrpos($string,".");
 566          if ($pos>=$length-4) {
 567              $string = substr($string,0,$length-4);
 568              $pos = strrpos($string,".");
 569          }
 570          if ($pos>=$length*0.4) {
 571              return substr($string,0,$pos+1)." ...";
 572          }
 573  
 574          $pos = strrpos($string," ");
 575          if ($pos>=$length-4) {
 576              $string = substr($string,0,$length-4);
 577              $pos = strrpos($string," ");
 578          }
 579          if ($pos>=$length*0.4) {
 580              return substr($string,0,$pos)." ...";
 581          }
 582  
 583          return substr($string,0,$length-4)." ...";
 584  
 585      }
 586  
 587  
 588      /**
 589       * Creates a comment indicating the generator of this feed.
 590       * The format of this comment seems to be recognized by
 591       * Syndic8.com.
 592       */
 593  	function _createGeneratorComment() {
 594          return "<!-- generator=\"".FEEDCREATOR_VERSION."\" -->\n";
 595      }
 596  
 597  
 598      /**
 599       * Creates a string containing all additional elements specified in
 600       * $additionalElements.
 601       * @param    elements    array    an associative array containing key => value pairs
 602       * @param indentString    string    a string that will be inserted before every generated line
 603       * @return    string    the XML tags corresponding to $additionalElements
 604       */
 605  	function _createAdditionalElements($elements, $indentString="") {
 606          $ae = "";
 607          if (is_array($elements)) {
 608              foreach($elements AS $key => $value) {
 609                  $ae.= $indentString."<$key>$value</$key>\n";
 610              }
 611          }
 612          return $ae;
 613      }
 614  
 615  	function _createStylesheetReferences() {
 616          $xml = "";
 617          if ($this->cssStyleSheet) $xml .= "<?xml-stylesheet href=\"".$this->cssStyleSheet."\" type=\"text/css\"?>\n";
 618          if ($this->xslStyleSheet) $xml .= "<?xml-stylesheet href=\"".$this->xslStyleSheet."\" type=\"text/xsl\"?>\n";
 619          return $xml;
 620      }
 621  
 622  
 623      /**
 624       * Builds the feed's text.
 625       * @abstract
 626       * @return    string    the feed's complete text
 627       */
 628  	function createFeed() {
 629      }
 630  
 631      /**
 632       * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml.
 633       * For example:
 634       *
 635       * echo $_SERVER["PHP_SELF"]."\n";
 636       * echo FeedCreator::_generateFilename();
 637       *
 638       * would produce:
 639       *
 640       * /rss/latestnews.php
 641       * latestnews.xml
 642       *
 643       * @return string the feed cache filename
 644       * @since 1.4
 645       * @access private
 646       */
 647  	function _generateFilename() {
 648          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
 649          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml";
 650      }
 651  
 652  
 653      /**
 654       * @since 1.4
 655       * @access private
 656       */
 657  	function _redirect($filename) {
 658          // attention, heavily-commented-out-area
 659  
 660          // maybe use this in addition to file time checking
 661          //Header("Expires: ".date("r",time()+$this->_timeout));
 662  
 663          /* no caching at all, doesn't seem to work as good:
 664          Header("Cache-Control: no-cache");
 665          Header("Pragma: no-cache");
 666          */
 667  
 668          // HTTP redirect, some feed readers' simple HTTP implementations don't follow it
 669          //Header("Location: ".$filename);
 670  
 671          //Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename));
 672          Header("Content-Type: ".$this->contentType."; charset=".$this->encoding);
 673          Header("Content-Disposition: inline; filename=".basename($filename));
 674          readfile($filename, "r");
 675          die();
 676      }
 677  
 678      /**
 679       * Turns on caching and checks if there is a recent version of this feed in the cache.
 680       * If there is, an HTTP redirect header is sent.
 681       * To effectively use caching, you should create the FeedCreator object and call this method
 682       * before anything else, especially before you do the time consuming task to build the feed
 683       * (web fetching, for example).
 684       * @since 1.4
 685       * @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()).
 686       * @param timeout    int        optional    the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
 687       */
 688  	function useCached($filename="", $timeout=3600) {
 689          $this->_timeout = $timeout;
 690          if ($filename=="") {
 691              $filename = $this->_generateFilename();
 692          }
 693          if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) {
 694              $this->_redirect($filename);
 695          }
 696      }
 697  
 698  
 699      /**
 700       * Saves this feed as a file on the local disk. After the file is saved, a redirect
 701       * header may be sent to redirect the user to the newly created file.
 702       * @since 1.4
 703       *
 704       * @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()).
 705       * @param redirect    boolean    optional    send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file.
 706       */
 707  	function saveFeed($filename="", $displayContents=true) {
 708          if ($filename=="") {
 709              $filename = $this->_generateFilename();
 710          }
 711          $feedFile = fopen($filename, "w+");
 712          if ($feedFile) {
 713              fputs($feedFile,$this->createFeed());
 714              fclose($feedFile);
 715              if ($displayContents) {
 716                  $this->_redirect($filename);
 717              }
 718          } else {
 719              echo "<br /><b>Error creating feed file, please check write permissions.</b><br />";
 720          }
 721      }
 722  
 723  }
 724  
 725  
 726  /**
 727   * FeedDate is an internal class that stores a date for a feed or feed item.
 728   * Usually, you won't need to use this.
 729   */
 730  class FeedDate {
 731      var $unix;
 732  
 733      /**
 734       * Creates a new instance of FeedDate representing a given date.
 735       * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps.
 736       * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used.
 737       */
 738  	function FeedDate($dateString="") {
 739          if ($dateString=="") $dateString = date("r");
 740  
 741          if (is_integer($dateString)) {
 742              $this->unix = $dateString;
 743              return;
 744          }
 745          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)) {
 746              $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);
 747              $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]);
 748              if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
 749                  $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
 750              } else {
 751                  if (strlen($matches[7])==1) {
 752                      $oneHour = 3600;
 753                      $ord = ord($matches[7]);
 754                      if ($ord < ord("M")) {
 755                          $tzOffset = (ord("A") - $ord - 1) * $oneHour;
 756                      } elseif ($ord >= ord("M") AND $matches[7]!="Z") {
 757                          $tzOffset = ($ord - ord("M")) * $oneHour;
 758                      } elseif ($matches[7]=="Z") {
 759                          $tzOffset = 0;
 760                      }
 761                  }
 762                  switch ($matches[7]) {
 763                      case "UT":
 764                      case "GMT":    $tzOffset = 0;
 765                  }
 766              }
 767              $this->unix += $tzOffset;
 768              return;
 769          }
 770          if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) {
 771              $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]);
 772              if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
 773                  $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
 774              } else {
 775                  if ($matches[7]=="Z") {
 776                      $tzOffset = 0;
 777                  }
 778              }
 779              $this->unix += $tzOffset;
 780              return;
 781          }
 782          $this->unix = 0;
 783      }
 784  
 785      /**
 786       * Gets the date stored in this FeedDate as an RFC 822 date.
 787       *
 788       * @return a date in RFC 822 format
 789       */
 790  	function rfc822() {
 791          //return gmdate("r",$this->unix);
 792          $date = gmdate("D, d M Y H:i:s", $this->unix);
 793          if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE);
 794          return $date;
 795      }
 796  
 797      /**
 798       * Gets the date stored in this FeedDate as an ISO 8601 date.
 799       *
 800       * @return a date in ISO 8601 format
 801       */
 802  	function iso8601() {
 803          $date = gmdate("Y-m-d\TH:i:sO",$this->unix);
 804          $date = substr($date,0,22) . ':' . substr($date,-2);
 805          if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date);
 806          return $date;
 807      }
 808  
 809      /**
 810       * Gets the date stored in this FeedDate as unix time stamp.
 811       *
 812       * @return a date as a unix time stamp
 813       */
 814  	function unix() {
 815          return $this->unix;
 816      }
 817  }
 818  
 819  
 820  /**
 821   * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0.
 822   *
 823   * @see http://www.purl.org/rss/1.0/
 824   * @since 1.3
 825   * @author Kai Blankenhorn <kaib@bitfolge.de>
 826   */
 827  class RSSCreator10 extends FeedCreator {
 828  
 829      /**
 830       * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
 831       * The feed will contain all items previously added in the same order.
 832       * @return    string    the feed's complete text
 833       */
 834  	function createFeed() {
 835          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
 836          $feed.= $this->_createGeneratorComment();
 837          if ($this->cssStyleSheet=="") {
 838              $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css";
 839          }
 840          $feed.= $this->_createStylesheetReferences();
 841          $feed.= "<rdf:RDF\n";
 842          $feed.= "    xmlns=\"http://purl.org/rss/1.0/\"\n";
 843          $feed.= "    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n";
 844          $feed.= "    xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n";
 845          $feed.= "    xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
 846          $feed.= "    <channel rdf:about=\"".$this->syndicationURL."\">\n";
 847          $feed.= "        <title>".htmlspecialchars($this->title)."</title>\n";
 848          $feed.= "        <description>".htmlspecialchars($this->description)."</description>\n";
 849          $feed.= "        <link>".$this->link."</link>\n";
 850          if ($this->image!=null) {
 851              $feed.= "        <image rdf:resource=\"".$this->image->url."\" />\n";
 852          }
 853          $now = new FeedDate();
 854          $feed.= "       <dc:date>".htmlspecialchars($now->iso8601())."</dc:date>\n";
 855          $feed.= "        <items>\n";
 856          $feed.= "            <rdf:Seq>\n";
 857          for ($i=0;$i<count($this->items);$i++) {
 858              $feed.= "                <rdf:li rdf:resource=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
 859          }
 860          $feed.= "            </rdf:Seq>\n";
 861          $feed.= "        </items>\n";
 862          $feed.= "    </channel>\n";
 863          if ($this->image!=null) {
 864              $feed.= "    <image rdf:about=\"".$this->image->url."\">\n";
 865              $feed.= "        <title>".$this->image->title."</title>\n";
 866              $feed.= "        <link>".$this->image->link."</link>\n";
 867              $feed.= "        <url>".$this->image->url."</url>\n";
 868              $feed.= "    </image>\n";
 869          }
 870          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
 871  
 872          for ($i=0;$i<count($this->items);$i++) {
 873              $feed.= "    <item rdf:about=\"".htmlspecialchars($this->items[$i]->link)."\">\n";
 874              //$feed.= "        <dc:type>Posting</dc:type>\n";
 875              $feed.= "        <dc:format>text/html</dc:format>\n";
 876              if ($this->items[$i]->date!=null) {
 877                  $itemDate = new FeedDate($this->items[$i]->date);
 878                  $feed.= "        <dc:date>".htmlspecialchars($itemDate->iso8601())."</dc:date>\n";
 879              }
 880              if ($this->items[$i]->source!="") {
 881                  $feed.= "        <dc:source>".htmlspecialchars($this->items[$i]->source)."</dc:source>\n";
 882              }
 883              if ($this->items[$i]->author!="") {
 884                  $feed.= "        <dc:creator>".htmlspecialchars($this->items[$i]->author)."</dc:creator>\n";
 885              }
 886              $feed.= "        <title>".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")))."</title>\n";
 887              $feed.= "        <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
 888              $feed.= "        <description>".htmlspecialchars($this->items[$i]->description)."</description>\n";
 889              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
 890              $feed.= "    </item>\n";
 891          }
 892          $feed.= "</rdf:RDF>\n";
 893          return $feed;
 894      }
 895  }
 896  
 897  
 898  
 899  /**
 900   * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3.
 901   *
 902   * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html
 903   * @since 1.3
 904   * @author Kai Blankenhorn <kaib@bitfolge.de>
 905   */
 906  class RSSCreator091 extends FeedCreator {
 907  
 908      /**
 909       * Stores this RSS feed's version number.
 910       * @access private
 911       */
 912      var $RSSVersion;
 913  
 914  	function RSSCreator091() {
 915          $this->_setRSSVersion("0.91");
 916          $this->contentType = "application/rss+xml";
 917      }
 918  
 919      /**
 920       * Sets this RSS feed's version number.
 921       * @access private
 922       */
 923  	function _setRSSVersion($version) {
 924          $this->RSSVersion = $version;
 925      }
 926  
 927      /**
 928       * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
 929       * The feed will contain all items previously added in the same order.
 930       * @return    string    the feed's complete text
 931       */
 932  	function createFeed() {
 933          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
 934          $feed.= $this->_createGeneratorComment();
 935          $feed.= $this->_createStylesheetReferences();
 936          $feed.= "<rss version=\"".$this->RSSVersion."\">\n";
 937          $feed.= "    <channel>\n";
 938          $feed.= "        <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
 939          $this->descriptionTruncSize = 500;
 940          $feed.= "        <description>".$this->getDescription()."</description>\n";
 941          $feed.= "        <link>".$this->link."</link>\n";
 942          $now = new FeedDate();
 943          $feed.= "        <lastBuildDate>".htmlspecialchars($now->rfc822())."</lastBuildDate>\n";
 944          $feed.= "        <generator>".FEEDCREATOR_VERSION."</generator>\n";
 945  
 946          if ($this->image!=null) {
 947              $feed.= "        <image>\n";
 948              $feed.= "            <url>".$this->image->url."</url>\n";
 949              $feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."</title>\n";
 950              $feed.= "            <link>".$this->image->link."</link>\n";
 951              if ($this->image->width!="") {
 952                  $feed.= "            <width>".$this->image->width."</width>\n";
 953              }
 954              if ($this->image->height!="") {
 955                  $feed.= "            <height>".$this->image->height."</height>\n";
 956              }
 957              if ($this->image->description!="") {
 958                  $feed.= "            <description>".$this->image->getDescription()."</description>\n";
 959              }
 960              $feed.= "        </image>\n";
 961          }
 962          if ($this->language!="") {
 963              $feed.= "        <language>".$this->language."</language>\n";
 964          }
 965          if ($this->copyright!="") {
 966              $feed.= "        <copyright>".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."</copyright>\n";
 967          }
 968          if ($this->editor!="") {
 969              $feed.= "        <managingEditor>".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."</managingEditor>\n";
 970          }
 971          if ($this->webmaster!="") {
 972              $feed.= "        <webMaster>".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."</webMaster>\n";
 973          }
 974          if ($this->pubDate!="") {
 975              $pubDate = new FeedDate($this->pubDate);
 976              $feed.= "        <pubDate>".htmlspecialchars($pubDate->rfc822())."</pubDate>\n";
 977          }
 978          if ($this->category!="") {
 979              $feed.= "        <category>".htmlspecialchars($this->category)."</category>\n";
 980          }
 981          if ($this->docs!="") {
 982              $feed.= "        <docs>".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."</docs>\n";
 983          }
 984          if ($this->ttl!="") {
 985              $feed.= "        <ttl>".htmlspecialchars($this->ttl)."</ttl>\n";
 986          }
 987          if (isset( $this->rating_count ) && $this->rating_count > 0) {
 988              $rating = round( $this->rating_sum / $this->rating_count );
 989              $feed.= "        <rating>".FeedCreator::iTrunc(htmlspecialchars($rating),500)."</rating>\n";
 990          }
 991          if ($this->skipHours!="") {
 992              $feed.= "        <skipHours>".htmlspecialchars($this->skipHours)."</skipHours>\n";
 993          }
 994          if ($this->skipDays!="") {
 995              $feed.= "        <skipDays>".htmlspecialchars($this->skipDays)."</skipDays>\n";
 996          }
 997          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
 998  
 999          for ($i=0;$i<count($this->items);$i++) {
1000              $feed.= "        <item>\n";
1001              $feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
1002              $feed.= "            <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
1003              $feed.= "            <description>".$this->items[$i]->getDescription()."</description>\n";
1004  
1005              if ($this->items[$i]->author!="") {
1006                  $feed.= "            <author>".htmlspecialchars($this->items[$i]->author)."</author>\n";
1007              }
1008              /*
1009              // on hold
1010              if ($this->items[$i]->source!="") {
1011                      $feed.= "            <source>".htmlspecialchars($this->items[$i]->source)."</source>\n";
1012              }
1013              */
1014              if ($this->items[$i]->category!="") {
1015                  $feed.= "            <category>".htmlspecialchars($this->items[$i]->category)."</category>\n";
1016              }
1017              if ($this->items[$i]->comments!="") {
1018                  $feed.= "            <comments>".htmlspecialchars($this->items[$i]->comments)."</comments>\n";
1019              }
1020              if ($this->items[$i]->date!="") {
1021              $itemDate = new FeedDate($this->items[$i]->date);
1022                  $feed.= "            <pubDate>".htmlspecialchars($itemDate->rfc822())."</pubDate>\n";
1023              }
1024              if ($this->items[$i]->guid!="") {
1025                  $feed.= "            <guid>".htmlspecialchars($this->items[$i]->guid)."</guid>\n";
1026              }
1027              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1028              $feed.= "        </item>\n";
1029          }
1030          $feed.= "    </channel>\n";
1031          $feed.= "</rss>\n";
1032          return $feed;
1033      }
1034  }
1035  
1036  
1037  
1038  /**
1039   * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0.
1040   *
1041   * @see http://backend.userland.com/rss
1042   * @since 1.3
1043   * @author Kai Blankenhorn <kaib@bitfolge.de>
1044   */
1045  class RSSCreator20 extends RSSCreator091 {
1046  
1047  	function RSSCreator20() {
1048          parent::_setRSSVersion("2.0");
1049      }
1050  
1051  }
1052  
1053  
1054  /**
1055   * PIECreator01 is a FeedCreator that implements the emerging PIE specification,
1056   * as in http://intertwingly.net/wiki/pie/Syntax.
1057   *
1058   * @deprecated
1059   * @since 1.3
1060   * @author Scott Reynen <scott@randomchaos.com> and Kai Blankenhorn <kaib@bitfolge.de>
1061   */
1062  class PIECreator01 extends FeedCreator {
1063  
1064  	function PIECreator01() {
1065          $this->encoding = "utf-8";
1066      }
1067  
1068  	function createFeed() {
1069          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1070          $feed.= $this->_createStylesheetReferences();
1071          $feed.= "<feed version=\"0.1\" xmlns=\"http://example.com/newformat#\">\n";
1072          $feed.= "    <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
1073          $this->truncSize = 500;
1074          $feed.= "    <subtitle>".$this->getDescription()."</subtitle>\n";
1075          $feed.= "    <link>".$this->link."</link>\n";
1076          for ($i=0;$i<count($this->items);$i++) {
1077              $feed.= "    <entry>\n";
1078              $feed.= "        <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
1079              $feed.= "        <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
1080              $itemDate = new FeedDate($this->items[$i]->date);
1081              $feed.= "        <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1082              $feed.= "        <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1083              $feed.= "        <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1084              $feed.= "        <id>".htmlspecialchars($this->items[$i]->guid)."</id>\n";
1085              if ($this->items[$i]->author!="") {
1086                  $feed.= "        <author>\n";
1087                  $feed.= "            <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1088                  if ($this->items[$i]->authorEmail!="") {
1089                      $feed.= "            <email>".$this->items[$i]->authorEmail."</email>\n";
1090                  }
1091                  $feed.="        </author>\n";
1092              }
1093              $feed.= "        <content type=\"text/html\" xml:lang=\"en-us\">\n";
1094              $feed.= "            <div xmlns=\"http://www.w3.org/1999/xhtml\">".$this->items[$i]->getDescription()."</div>\n";
1095              $feed.= "        </content>\n";
1096              $feed.= "    </entry>\n";
1097          }
1098          $feed.= "</feed>\n";
1099          return $feed;
1100      }
1101  }
1102  
1103  
1104  /**
1105   * AtomCreator03 is a FeedCreator that implements the atom specification,
1106   * as in http://www.intertwingly.net/wiki/pie/FrontPage.
1107   * Please note that just by using AtomCreator03 you won't automatically
1108   * produce valid atom files. For example, you have to specify either an editor
1109   * for the feed or an author for every single feed item.
1110   *
1111   * Some elements have not been implemented yet. These are (incomplete list):
1112   * author URL, item author's email and URL, item contents, alternate links,
1113   * other link content types than text/html. Some of them may be created with
1114   * AtomCreator03::additionalElements.
1115   *
1116   * @see FeedCreator#additionalElements
1117   * @since 1.6
1118   * @author Kai Blankenhorn <kaib@bitfolge.de>, Scott Reynen <scott@randomchaos.com>
1119   */
1120  class AtomCreator03 extends FeedCreator {
1121  
1122  	function AtomCreator03() {
1123          $this->contentType = "application/atom+xml";
1124          $this->encoding = "utf-8";
1125      }
1126  
1127  	function createFeed() {
1128          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1129          $feed.= $this->_createGeneratorComment();
1130          $feed.= $this->_createStylesheetReferences();
1131          $feed.= "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\"";
1132          if ($this->language!="") {
1133              $feed.= " xml:lang=\"".$this->language."\"";
1134          }
1135          $feed.= ">\n";
1136          $feed.= "    <title>".htmlspecialchars($this->title)."</title>\n";
1137          $feed.= "    <tagline>".htmlspecialchars($this->description)."</tagline>\n";
1138          $feed.= "    <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link)."\"/>\n";
1139          $feed.= "    <id>".htmlspecialchars($this->link)."</id>\n";
1140          $now = new FeedDate();
1141          $feed.= "    <modified>".htmlspecialchars($now->iso8601())."</modified>\n";
1142          if ($this->editor!="") {
1143              $feed.= "    <author>\n";
1144              $feed.= "        <name>".$this->editor."</name>\n";
1145              if ($this->editorEmail!="") {
1146                  $feed.= "        <email>".$this->editorEmail."</email>\n";
1147              }
1148              $feed.= "    </author>\n";
1149          }
1150          $feed.= "    <generator>".FEEDCREATOR_VERSION."</generator>\n";
1151          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
1152          for ($i=0;$i<count($this->items);$i++) {
1153              $feed.= "    <entry>\n";
1154              $feed.= "        <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n";
1155              $feed.= "        <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
1156              if ($this->items[$i]->date=="") {
1157                  $this->items[$i]->date = time();
1158              }
1159              $itemDate = new FeedDate($this->items[$i]->date);
1160              $feed.= "        <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1161              $feed.= "        <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1162              $feed.= "        <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1163              $feed.= "        <id>".htmlspecialchars($this->items[$i]->link)."</id>\n";
1164              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1165              if ($this->items[$i]->author!="") {
1166                  $feed.= "        <author>\n";
1167                  $feed.= "            <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1168                  $feed.= "        </author>\n";
1169              }
1170              if ($this->items[$i]->description!="") {
1171                  $feed.= "        <summary>".htmlspecialchars($this->items[$i]->description)."</summary>\n";
1172              }
1173              $feed.= "    </entry>\n";
1174          }
1175          $feed.= "</feed>\n";
1176          return $feed;
1177      }
1178  }
1179  
1180  
1181  /**
1182   * MBOXCreator is a FeedCreator that implements the mbox format
1183   * as described in http://www.qmail.org/man/man5/mbox.html
1184   *
1185   * @since 1.3
1186   * @author Kai Blankenhorn <kaib@bitfolge.de>
1187   */
1188  class MBOXCreator extends FeedCreator {
1189  
1190  	function MBOXCreator() {
1191          $this->contentType = "text/plain";
1192          $this->encoding = "ISO-8859-15";
1193      }
1194  
1195  	function qp_enc($input = "", $line_max = 76) {
1196          $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1197          $lines = preg_split("/(?:\r\n|\r|\n)/", $input);
1198          $eol = "\r\n";
1199          $escape = "=";
1200          $output = "";
1201          while( list(, $line) = each($lines) ) {
1202              //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary
1203              $linlen = strlen($line);
1204              $newline = "";
1205              for($i = 0; $i < $linlen; $i++) {
1206                  $c = substr($line, $i, 1);
1207                  $dec = ord($c);
1208                  if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only
1209                      $c = "=20";
1210                  } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
1211                      $h2 = floor($dec/16); $h1 = floor($dec%16);
1212                      $c = $escape.$hex["$h2"].$hex["$h1"];
1213                  }
1214                  if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
1215                      $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
1216                      $newline = "";
1217                  }
1218                  $newline .= $c;
1219              } // end of for
1220              $output .= $newline.$eol;
1221          }
1222          return trim($output);
1223      }
1224  
1225  
1226      /**
1227       * Builds the MBOX contents.
1228       * @return    string    the feed's complete text
1229       */
1230  	function createFeed() {
1231          for ($i=0;$i<count($this->items);$i++) {
1232              if ($this->items[$i]->author!="") {
1233                  $from = $this->items[$i]->author;
1234              } else {
1235                  $from = $this->title;
1236              }
1237              $itemDate = new FeedDate($this->items[$i]->date);
1238              $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n";
1239              $feed.= "Content-Type: text/plain;\n";
1240              $feed.= "    charset=\"".$this->encoding."\"\n";
1241              $feed.= "Content-Transfer-Encoding: quoted-printable\n";
1242              $feed.= "Content-Type: text/plain\n";
1243              $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n";
1244              $feed.= "Date: ".$itemDate->rfc822()."\n";
1245              $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n";
1246              $feed.= "\n";
1247              $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description));
1248              $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body);
1249              $feed.= "\n";
1250              $feed.= "\n";
1251          }
1252          return $feed;
1253      }
1254  
1255      /**
1256       * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types.
1257       * @return string the feed cache filename
1258       * @since 1.4
1259       * @access private
1260       */
1261  	function _generateFilename() {
1262          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1263          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox";
1264      }
1265  }
1266  
1267  
1268  /**
1269   * OPMLCreator is a FeedCreator that implements OPML 1.0.
1270   *
1271   * @see http://opml.scripting.com/spec
1272   * @author Dirk Clemens, Kai Blankenhorn
1273   * @since 1.5
1274   */
1275  class OPMLCreator extends FeedCreator {
1276  
1277  	function OPMLCreator() {
1278          $this->encoding = "utf-8";
1279      }
1280  
1281  	function createFeed() {
1282          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1283          $feed.= $this->_createGeneratorComment();
1284          $feed.= $this->_createStylesheetReferences();
1285          $feed.= "<opml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
1286          $feed.= "    <head>\n";
1287          $feed.= "        <title>".htmlspecialchars($this->title)."</title>\n";
1288          if ($this->pubDate!="") {
1289              $date = new FeedDate($this->pubDate);
1290              $feed.= "         <dateCreated>".$date->rfc822()."</dateCreated>\n";
1291          }
1292          if ($this->lastBuildDate!="") {
1293              $date = new FeedDate($this->lastBuildDate);
1294              $feed.= "         <dateModified>".$date->rfc822()."</dateModified>\n";
1295          }
1296          if ($this->editor!="") {
1297              $feed.= "         <ownerName>".$this->editor."</ownerName>\n";
1298          }
1299          if ($this->editorEmail!="") {
1300              $feed.= "         <ownerEmail>".$this->editorEmail."</ownerEmail>\n";
1301          }
1302          $feed.= "    </head>\n";
1303          $feed.= "    <body>\n";
1304          for ($i=0;$i<count($this->items);$i++) {
1305              $feed.= "    <outline type=\"rss\" ";
1306              $title = htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")));
1307              $feed.= " title=\"".$title."\"";
1308              $feed.= " text=\"".$title."\"";
1309              //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\"";
1310              $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\"";
1311              $feed.= "/>\n";
1312          }
1313          $feed.= "    </body>\n";
1314          $feed.= "</opml>\n";
1315          return $feed;
1316      }
1317  }
1318  
1319  
1320  
1321  /**
1322   * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific
1323   * location, overriding the createFeed method of the parent FeedCreator.
1324   * The HTML produced can be included over http by scripting languages, or serve
1325   * as the source for an IFrame.
1326   * All output by this class is embedded in <div></div> tags to enable formatting
1327   * using CSS.
1328   *
1329   * @author Pascal Van Hecke
1330   * @since 1.7
1331   */
1332  class HTMLCreator extends FeedCreator {
1333  
1334      var $contentType = "text/html";
1335  
1336      /**
1337       * Contains HTML to be output at the start of the feed's html representation.
1338       */
1339      var $header;
1340  
1341      /**
1342       * Contains HTML to be output at the end of the feed's html representation.
1343       */
1344      var $footer ;
1345  
1346      /**
1347       * Contains HTML to be output between entries. A separator is only used in
1348       * case of multiple entries.
1349       */
1350      var $separator;
1351  
1352      /**
1353       * Used to prefix the stylenames to make sure they are unique
1354       * and do not clash with stylenames on the users' page.
1355       */
1356      var $stylePrefix;
1357  
1358      /**
1359       * Determines whether the links open in a new window or not.
1360       */
1361      var $openInNewWindow = true;
1362  
1363      var $imageAlign ="right";
1364  
1365      /**
1366       * In case of very simple output you may want to get rid of the style tags,
1367       * hence this variable.  There's no equivalent on item level, but of course you can
1368       * add strings to it while iterating over the items ($this->stylelessOutput .= ...)
1369       * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored
1370       * in the function createFeed().
1371       */
1372      var $stylelessOutput ="";
1373  
1374      /**
1375       * Writes the HTML.
1376       * @return    string    the scripts's complete text
1377       */
1378  	function createFeed() {
1379          // if there is styleless output, use the content of this variable and ignore the rest
1380          if ($this->stylelessOutput!="") {
1381              return $this->stylelessOutput;
1382          }
1383  
1384          //if no stylePrefix is set, generate it yourself depending on the script name
1385          if ($this->stylePrefix=="") {
1386              $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_";
1387          }
1388  
1389          //set an openInNewWindow_token_to be inserted or not
1390          if ($this->openInNewWindow) {
1391              $targetInsert = " target='_blank'";
1392          }
1393  
1394          // use this array to put the lines in and implode later with "document.write" javascript
1395          $feedArray = array();
1396          if ($this->image!=null) {
1397              $imageStr = "<a href='".$this->image->link."'".$targetInsert.">".
1398                              "<img src='".$this->image->url."' border='0' alt='".
1399                              FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
1400                              "' align='".$this->imageAlign."' ";
1401              if ($this->image->width) {
1402                  $imageStr .=" width='".$this->image->width. "' ";
1403              }
1404              if ($this->image->height) {
1405                  $imageStr .=" height='".$this->image->height."' ";
1406              }
1407              $imageStr .="/></a>";
1408              $feedArray[] = $imageStr;
1409          }
1410  
1411          if ($this->title) {
1412              $feedArray[] = "<div class='".$this->stylePrefix."title'><a href='".$this->link."' ".$targetInsert." class='".$this->stylePrefix."title'>".
1413                  FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</a></div>";
1414          }
1415          if ($this->getDescription()) {
1416              $feedArray[] = "<div class='".$this->stylePrefix."description'>".
1417                  str_replace("]]>", "", str_replace("<![CDATA[", "", $this->getDescription())).
1418                  "</div>";
1419          }
1420  
1421          if ($this->header) {
1422              $feedArray[] = "<div class='".$this->stylePrefix."header'>".$this->header."</div>";
1423          }
1424  
1425          for ($i=0;$i<count($this->items);$i++) {
1426              if ($this->separator and $i > 0) {
1427                  $feedArray[] = "<div class='".$this->stylePrefix."separator'>".$this->separator."</div>";
1428              }
1429  
1430              if ($this->items[$i]->title) {
1431                  if ($this->items[$i]->link) {
1432                      $feedArray[] =
1433                          "<div class='".$this->stylePrefix."item_title'><a href='".$this->items[$i]->link."' class='".$this->stylePrefix.
1434                          "item_title'".$targetInsert.">".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
1435                          "</a></div>";
1436                  } else {
1437                      $feedArray[] =
1438                          "<div class='".$this->stylePrefix."item_title'>".
1439                          FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
1440                          "</div>";
1441                  }
1442              }
1443              if ($this->items[$i]->getDescription()) {
1444                  $feedArray[] =
1445                  "<div class='".$this->stylePrefix."item_description'>".
1446                      str_replace("]]>", "", str_replace("<![CDATA[", "", $this->items[$i]->getDescription())).
1447                      "</div>";
1448              }
1449          }
1450          if ($this->footer) {
1451              $feedArray[] = "<div class='".$this->stylePrefix."footer'>".$this->footer."</div>";
1452          }
1453  
1454          $feed= "".join($feedArray, "\r\n");
1455          return $feed;
1456      }
1457  
1458      /**
1459       * Overrrides parent to produce .html extensions
1460       *
1461       * @return string the feed cache filename
1462       * @since 1.4
1463       * @access private
1464       */
1465  	function _generateFilename() {
1466          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1467          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html";
1468      }
1469  }
1470  
1471  
1472  /**
1473   * JSCreator is a class that writes a js file to a specific
1474   * location, overriding the createFeed method of the parent HTMLCreator.
1475   *
1476   * @author Pascal Van Hecke
1477   */
1478  class JSCreator extends HTMLCreator {
1479      var $contentType = "text/javascript";
1480  
1481      /**
1482       * writes the javascript
1483       * @return    string    the scripts's complete text
1484       */
1485  	function createFeed()
1486      {
1487          $feed = parent::createFeed();
1488          $feedArray = explode("\n",$feed);
1489  
1490          $jsFeed = "";
1491          foreach ($feedArray as $value) {
1492              $jsFeed .= "document.write('".trim(addslashes($value))."');\n";
1493          }
1494          return $jsFeed;
1495      }
1496  
1497      /**
1498       * Overrrides parent to produce .js extensions
1499       *
1500       * @return string the feed cache filename
1501       * @since 1.4
1502       * @access private
1503       */
1504  	function _generateFilename() {
1505          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1506          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js";
1507      }
1508  
1509  }
1510  
1511  
1512  /**
1513  * GoogleSiteMapIndex is a FeedCreator that implements Google Sitemap Index 0.84.
1514  *
1515  * @see https://www.google.com/webmasters/sitemaps/docs/en/protocol.html#sitemapFileRequirements
1516  * taken from http://phpbb.bitfolge.de/viewtopic.php?t=102
1517  */
1518  class GoogleSiteMapIndex extends FeedCreator {
1519      /**
1520      * Builds the Google Sitemap feed's text.
1521      * The feed will contain all items previously added in the same order.
1522      * @return string the feed's complete text
1523      */
1524  	function createFeed() {
1525          $feed     = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
1526          $feed    .= "<sitemapindex xmlns=\"http://www.google.com/schemas/sitemap/0.84\"\n";
1527          $feed    .= "              xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
1528          $feed    .= "              xsi:schemaLocation=\"http://www.google.com/schemas/sitemap/0.84\n";
1529          $feed    .= "              http://www.google.com/schemas/sitemap/0.84/siteindex.xsd\">\n";
1530  
1531          $total = count( $this->items ) ;
1532          for ( $i=0; $i < $total; $i++ ) {
1533              $feed    .= "  <sitemap>\n";
1534              $feed    .= "    <loc>".htmlspecialchars($this->items[$i]->link)."</loc>\n";
1535              if ( $this->items[$i]->date != "" ) {
1536                  $itemDate     = new FeedDate( $this->items[$i]->date );
1537                  $feed        .= "    <lastmod>".htmlspecialchars($itemDate->iso8601())."</lastmod>\n";
1538              }
1539              $feed.= "  </sitemap>\n";
1540          }
1541          $feed.= "</sitemapindex>\n";
1542  
1543          return $feed;
1544      }
1545  }
1546  
1547  /*** TEST SCRIPT *********************************************************
1548  
1549  //include("feedcreator.class.php");
1550  
1551  $rss = new UniversalFeedCreator();
1552  $rss->useCached();
1553  $rss->title = "PHP news";
1554  $rss->description = "daily news from the PHP scripting world";
1555  
1556  //optional
1557  //$rss->descriptionTruncSize = 500;
1558  //$rss->descriptionHtmlSyndicated = true;
1559  //$rss->xslStyleSheet = "http://feedster.com/rss20.xsl";
1560  
1561  $rss->link = "http://www.dailyphp.net/news";
1562  $rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF;
1563  
1564  $image = new FeedImage();
1565  $image->title = "dailyphp.net logo";
1566  $image->url = "http://www.dailyphp.net/images/logo.gif";
1567  $image->link = "http://www.dailyphp.net";
1568  $image->description = "Feed provided by dailyphp.net. Click to visit.";
1569  
1570  //optional
1571  $image->descriptionTruncSize = 500;
1572  $image->descriptionHtmlSyndicated = true;
1573  
1574  $rss->image = $image;
1575  
1576  // get your news items from somewhere, e.g. your database:
1577  //mysql_select_db($dbHost, $dbUser, $dbPass);
1578  //$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");
1579  //while ($data = mysql_fetch_object($res)) {
1580      $item = new FeedItem();
1581      $item->title = "This is an the test title of an item";
1582      $item->link = "http://localhost/item/";
1583      $item->description = "<b>description in </b><br/>HTML";
1584  
1585      //optional
1586      //item->descriptionTruncSize = 500;
1587      $item->descriptionHtmlSyndicated = true;
1588  
1589      $item->date = time();
1590      $item->source = "http://www.dailyphp.net";
1591      $item->author = "John Doe";
1592  
1593      $rss->addItem($item);
1594  //}
1595  
1596  // valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS
1597  echo $rss->saveFeed("RSS0.91", "feed.xml");
1598  
1599  
1600  
1601  ***************************************************************************/
1602  ?>


Généré le : Wed Nov 21 14:43:32 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics