Syntax Desktop PHP Cross Reference Web Portal Systems

Source: /public/lib/feedcreator.class.php - 1778 lines - 58969 bytes - Summary - Text - Print

Description: Version string.

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

   3  

   4  FeedCreator class v1.7.2-ppt

   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  v1.7.2-mod on-the-fly feed generation by Fabian Wolf (info@f2w.de)

  11  v1.7.2-ppt ATOM 1.0 support by Mohammad Hafiz bin Ismail (mypapit@gmail.com)

  12  

  13  This library is free software; you can redistribute it and/or

  14  modify it under the terms of the GNU Lesser General Public

  15  License as published by the Free Software Foundation; either

  16  version 2.1 of the License, or (at your option) any later version.

  17  

  18  This library is distributed in the hope that it will be useful,

  19  but WITHOUT ANY WARRANTY; without even the implied warranty of

  20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

  21  Lesser General Public License for more details.

  22  

  23  You should have received a copy of the GNU Lesser General Public

  24  License along with this library; if not, write to the Free Software

  25  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  26  

  27  ****************************************************************************

  28  

  29  

  30  Changelog:

  31  

  32  v1.7.2-ppt    11-21-05 

  33      added Atom 1.0 support

  34      added enclosure support for RSS 2.0/ATOM 1.0

  35      added docs for v1.7.2-ppt only! 

  36      

  37  v1.7.2-mod    03-12-05

  38      added output function outputFeed for on-the-fly feed generation

  39  

  40  v1.7.2    10-11-04

  41      license changed to LGPL

  42  

  43  v1.7.1

  44      fixed a syntax bug

  45      fixed left over debug code

  46  

  47  v1.7    07-18-04

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

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

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

  51      changed default content-type to application/xml

  52      added character encoding setting

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

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

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

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

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

  58  

  59  v1.6    05-10-04

  60      added stylesheet to RSS 1.0 feeds

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

  62      fixed RFC822 date bug (thanks Tanguy Pruvot)

  63      added TimeZone customization for RFC8601 (thanks Tanguy Pruvot)

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

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

  66  

  67  v1.6 beta    02-28-04

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

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

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

  71      code beautification :-)

  72      considered beta due to some internal changes

  73  

  74  v1.5.1    01-27-04

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

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

  77  

  78  v1.5    01-06-04

  79      added support for OPML 1.0

  80      added more documentation

  81  

  82  v1.4    11-11-03

  83      optional feed saving and caching

  84      improved documentation

  85      minor improvements

  86  

  87  v1.3    10-02-03

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

  89      added support for mbox

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

  91          

  92  v1.2    07-20-03

  93      intelligent auto-truncating of RSS 0.91 attributes

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

  95      documentation improved

  96      fixed a real and a possible bug with date conversions

  97      code cleanup

  98  

  99  v1.1    06-29-03

 100      added images to feeds

 101      now includes most RSS 0.91 attributes

 102      added RSS 2.0 feeds

 103  

 104  v1.0    06-24-03

 105      initial release

 106  

 107  

 108  

 109  ***************************************************************************/
 110  
 111  /*** GENERAL USAGE *********************************************************

 112  

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

 114  

 115  $rss = new UniversalFeedCreator(); 

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

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

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

 119  

 120  //optional

 121  $rss->descriptionTruncSize = 500;

 122  $rss->descriptionHtmlSyndicated = true;

 123  

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

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

 126  

 127  $image = new FeedImage(); 

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

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

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

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

 132  

 133  //optional

 134  $image->descriptionTruncSize = 500;

 135  $image->descriptionHtmlSyndicated = true;

 136  

 137  $rss->image = $image; 

 138  

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

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

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

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

 143      $item = new FeedItem(); 

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

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

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

 147      

 148      //optional

 149      item->descriptionTruncSize = 500;

 150      item->descriptionHtmlSyndicated = true;

 151      

 152      //optional (enclosure)

 153      $item->enclosure = new EnclosureItem();

 154      $item->enclosure->url='http://http://www.dailyphp.net/media/voice.mp3';

 155      $item->enclosure->length="950230";

 156      $item->enclosure->type='audio/x-mpeg'

 157      

 158      

 159  

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

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

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

 163       

 164      $rss->addItem($item); 

 165  } 

 166  

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

 168  // MBOX, OPML, ATOM, ATOM10, ATOM0.3, HTML, JS

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

 170  

 171  //to generate "on-the-fly"

 172  $rss->outputFeed("RSS1.0");

 173  

 174  

 175  ***************************************************************************

 176  *          A little setup                                                 *

 177  **************************************************************************/
 178  
 179  // your local timezone, set to "" to disable or for GMT

 180  define("TIME_ZONE","+01:00");
 181  
 182  
 183  
 184  
 185  /**

 186   * Version string.

 187   **/
 188   
 189  define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2-ppt (info@mypapit.net)");
 190  
 191  
 192  
 193  /**

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

 195   *

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

 197   * @since 1.3

 198   */
 199  class FeedItem extends HtmlDescribable {
 200      /**

 201       * Mandatory attributes of an item.

 202       */
 203      var $title, $description, $link;
 204      
 205      /**

 206       * Optional attributes of an item.

 207       */
 208      var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator;
 209      
 210      /**

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

 212       *

 213       *    RFC 822:

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

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

 216       *

 217       *    ISO 8601:

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

 219       *

 220       *    Unix:

 221       *    1043082341

 222       */
 223      var $date;
 224      
 225      /**

 226       * Add <enclosure> element tag RSS 2.0

 227       * modified by : Mohammad Hafiz bin Ismail (mypapit@gmail.com)

 228       *

 229       *

 230       * display :

 231       * <enclosure length="17691" url="http://something.com/picture.jpg" type="image/jpeg" />

 232       * 

 233       */
 234      var $enclosure;
 235      
 236      /**

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

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

 239       *     <$key>$value</$key>

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

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

 242       * the FeedCreator class used.

 243       */
 244      var $additionalElements = Array();
 245  
 246      // on hold

 247      // var $source;

 248  }
 249  
 250  class EnclosureItem extends HtmlDescribable {
 251      /*

 252      * 

 253      * core variables

 254      *

 255      **/
 256      var $url,$length,$type;
 257      
 258      /*

 259      * For use with another extension like Yahoo mRSS

 260      * Warning :

 261      * These variables might not show up in 

 262      * later release / not finalize yet!

 263      *

 264      */
 265      var $width, $height, $title, $description, $keywords, $thumburl;
 266      
 267      var $additionalElements = Array();
 268  
 269  }
 270  
 271  
 272  /**

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

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

 275   * @since 1.3

 276   */
 277  class FeedImage extends HtmlDescribable {
 278      /**

 279       * Mandatory attributes of an image.

 280       */
 281      var $title, $url, $link;
 282      
 283      /**

 284       * Optional attributes of an image.

 285       */
 286      var $width, $height, $description;
 287  }
 288  
 289  
 290  
 291  /**

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

 293   * include HTML markup.

 294   */
 295  class HtmlDescribable {
 296      /**

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

 298       */
 299      var $descriptionHtmlSyndicated;
 300      
 301      /**

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

 303       */
 304      var $descriptionTruncSize;
 305      
 306      /**

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

 308       * $descriptionTruncSize properties

 309       * @return    string    the formatted description  

 310       */
 311  	function getDescription() {
 312          $descriptionField = new FeedHtmlField($this->description);
 313          $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated;
 314          $descriptionField->truncSize = $this->descriptionTruncSize;
 315          return $descriptionField->output();
 316      }
 317  
 318  }
 319  
 320  
 321  
 322  /**

 323   * An FeedHtmlField describes and generates

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

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

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

 327   * @version 1.6

 328   */
 329  class FeedHtmlField {
 330      /**

 331       * Mandatory attributes of a FeedHtmlField.

 332       */
 333      var $rawFieldContent;
 334      
 335      /**

 336       * Optional attributes of a FeedHtmlField.

 337       * 

 338       */
 339      var $truncSize, $syndicateHtml;
 340      
 341      /**

 342       * Creates a new instance of FeedHtmlField.

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

 344       */
 345  	function FeedHtmlField($parFieldContent) {
 346          if ($parFieldContent) {
 347              $this->rawFieldContent = $parFieldContent;
 348          }
 349      }
 350          
 351          
 352      /**

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

 354       * @return string    the formatted field

 355       */
 356  	function output() {
 357          // when field available and syndicated in html we assume 

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

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

 360          if (!$this->rawFieldContent) {
 361              $result = "";
 362          }    elseif ($this->syndicateHtml) {
 363              $result = "<![CDATA[".$this->rawFieldContent."]]>";
 364          } else {
 365              if ($this->truncSize and is_int($this->truncSize)) {
 366                  $result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize);
 367              } else {
 368                  $result = htmlspecialchars($this->rawFieldContent);
 369              }
 370          }
 371          return $result;
 372      }
 373  
 374  }
 375  
 376  
 377  
 378  /**

 379   * UniversalFeedCreator lets you choose during runtime which

 380   * format to build.

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

 382   * below or the example above.

 383   *

 384   * @since 1.3

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

 386   */
 387  class UniversalFeedCreator extends FeedCreator {
 388      var $_feed;
 389      
 390  	function _setMIME($format) {
 391          switch (strtoupper($format)) {
 392              
 393              case "2.0":
 394                  // fall through

 395              case "RSS2.0":
 396                  header('Content-type: text/xml', true);
 397                  break;
 398              
 399              case "1.0":
 400                  // fall through

 401              case "RSS1.0":
 402                  header('Content-type: text/xml', true);
 403                  break;
 404              
 405              case "PIE0.1":
 406                  header('Content-type: text/xml', true);
 407                  break;
 408              
 409              case "MBOX":
 410                  header('Content-type: text/plain', true);
 411                  break;
 412              
 413              case "OPML":
 414                  header('Content-type: text/xml', true);
 415                  break;
 416                  
 417              case "ATOM":
 418                  // fall through: always the latest ATOM version

 419              case "ATOM1.0":
 420                  header('Content-type: application/xml', true);
 421                  break;
 422                  
 423              case "ATOM0.3":
 424                  header('Content-type: application/xml', true);
 425                  break;
 426      
 427                  
 428              case "HTML":
 429                  header('Content-type: text/html', true);
 430                  break;
 431              
 432              case "JS":
 433                  // fall through

 434              case "JAVASCRIPT":
 435                  header('Content-type: text/javascript', true);
 436                  break;
 437  
 438              default:
 439              case "0.91":
 440                  // fall through

 441              case "RSS0.91":
 442                  header('Content-type: text/xml', true);
 443                  break;
 444          }
 445      }
 446      
 447  	function _setFormat($format) {
 448          switch (strtoupper($format)) {
 449              
 450              case "2.0":
 451                  // fall through

 452              case "RSS2.0":
 453                  $this->_feed = new RSSCreator20();
 454                  break;
 455              
 456              case "1.0":
 457                  // fall through

 458              case "RSS1.0":
 459                  $this->_feed = new RSSCreator10();
 460                  break;
 461              
 462              case "0.91":
 463                  // fall through

 464              case "RSS0.91":
 465                  $this->_feed = new RSSCreator091();
 466                  break;
 467              
 468              case "PIE0.1":
 469                  $this->_feed = new PIECreator01();
 470                  break;
 471              
 472              case "MBOX":
 473                  $this->_feed = new MBOXCreator();
 474                  break;
 475              
 476              case "OPML":
 477                  $this->_feed = new OPMLCreator();
 478                  break;
 479                  
 480              case "ATOM":
 481                  // fall through: always the latest ATOM version

 482              case "ATOM1.0":
 483                  $this->_feed = new AtomCreator10();
 484                  break;
 485              
 486                  
 487              case "ATOM0.3":
 488                  $this->_feed = new AtomCreator03();
 489                  break;
 490                              
 491              case "HTML":
 492                  $this->_feed = new HTMLCreator();
 493                  break;
 494              
 495              case "JS":
 496                  // fall through

 497              case "JAVASCRIPT":
 498                  $this->_feed = new JSCreator();
 499                  break;
 500              
 501              default:
 502                  $this->_feed = new RSSCreator091();
 503                  break;
 504          }
 505          
 506          $vars = get_object_vars($this);
 507          foreach ($vars as $key => $value) {
 508              // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself

 509              if (!in_array($key, array("_feed", "contentType", "encoding"))) {
 510                  $this->_feed->{$key} = $this->{$key};
 511              }
 512          }
 513      }
 514      
 515      /**

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

 517       *

 518       * @see        FeedCreator::addItem()

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

 520       *            "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS"

 521       * @return    string    the contents of the feed.

 522       */
 523  	function createFeed($format = "RSS0.91") {
 524          $this->_setFormat($format);
 525          return $this->_feed->createFeed();
 526      }
 527      
 528      
 529      
 530      /**

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

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

 533       * @since 1.4

 534       * 

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

 536       *            "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS"

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

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

 539       */
 540  	function saveFeed($format="RSS0.91", $filename="", $displayContents=true) {
 541          $this->_setFormat($format);
 542          $this->_feed->saveFeed($filename, $displayContents);
 543      }
 544  
 545  
 546     /**

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

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

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

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

 551      * (web fetching, for example).

 552      *

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

 554      *       "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3".

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

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

 557      */
 558     function useCached($format="RSS0.91", $filename="", $timeout=3600) {
 559        $this->_setFormat($format);
 560        $this->_feed->useCached($filename, $timeout);
 561     }
 562  
 563     
 564     /**

 565      * Outputs feed to the browser - needed for on-the-fly feed generation (like it is done in WordPress, etc.)

 566      *

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

 568      *                             "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3".

 569      */
 570     function outputFeed($format='RSS0.91') {
 571          $this->_setFormat($format);
 572          $this->_setMIME($format);
 573          $this->_feed->outputFeed();
 574     }
 575     
 576     
 577  }
 578  
 579  
 580  /**

 581   * FeedCreator is the abstract base implementation for concrete

 582   * implementations that implement a specific format of syndication.

 583   *

 584   * @abstract

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

 586   * @since 1.4

 587   */
 588  class FeedCreator extends HtmlDescribable {
 589  
 590      /**

 591       * Mandatory attributes of a feed.

 592       */
 593      var $title, $description, $link;
 594      
 595      
 596      /**

 597       * Optional attributes of a feed.

 598       */
 599      var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays;
 600  
 601      /**

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

 603      * Ignored in the output when empty.

 604      */
 605      var $xslStyleSheet = "";
 606      
 607      
 608      /**

 609       * @access private

 610       */
 611      var $items = Array();
 612       
 613      
 614      /**

 615       * This feed's MIME content type.

 616       * @since 1.4

 617       * @access private

 618       */
 619      var $contentType = "application/xml";
 620      
 621      
 622      /**

 623       * This feed's character encoding.

 624       * @since 1.6.1

 625       **/
 626      var $encoding = "ISO-8859-1";
 627      
 628      
 629      /**

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

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

 632       *     <$key>$value</$key>

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

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

 635       * the FeedCreator class used.

 636       */
 637      var $additionalElements = Array();
 638     
 639      
 640      /**

 641       * Adds an FeedItem to the feed.

 642       *

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

 644       * @access public

 645       */
 646  	function addItem($item) {
 647          $this->items[] = $item;
 648      }
 649      
 650      
 651      /**

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

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

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

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

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

 657       * 

 658       * @static

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

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

 661       * @return string    the truncated string

 662       */
 663  	function iTrunc($string, $length) {
 664          if (strlen($string)<=$length) {
 665              return $string;
 666          }
 667          
 668          $pos = strrpos($string,".");
 669          if ($pos>=$length-4) {
 670              $string = substr($string,0,$length-4);
 671              $pos = strrpos($string,".");
 672          }
 673          if ($pos>=$length*0.4) {
 674              return substr($string,0,$pos+1)." ...";
 675          }
 676          
 677          $pos = strrpos($string," ");
 678          if ($pos>=$length-4) {
 679              $string = substr($string,0,$length-4);
 680              $pos = strrpos($string," ");
 681          }
 682          if ($pos>=$length*0.4) {
 683              return substr($string,0,$pos)." ...";
 684          }
 685          
 686          return substr($string,0,$length-4)." ...";
 687              
 688      }
 689      
 690      
 691      /**

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

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

 694       * Syndic8.com.

 695       */
 696  	function _createGeneratorComment() {
 697          return "<!-- generator=\"".FEEDCREATOR_VERSION."\" -->\n";
 698      }
 699      
 700      
 701      /**

 702       * Creates a string containing all additional elements specified in

 703       * $additionalElements.

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

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

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

 707       */
 708  	function _createAdditionalElements($elements, $indentString="") {
 709          $ae = "";
 710          if (is_array($elements)) {
 711              foreach($elements AS $key => $value) {
 712                  $ae.= $indentString."<$key>$value</$key>\n";
 713              }
 714          }
 715          return $ae;
 716      }
 717      
 718  	function _createStylesheetReferences() {
 719          $xml = "";
 720          if ($this->cssStyleSheet) $xml .= "<?xml-stylesheet href=\"".$this->cssStyleSheet."\" type=\"text/css\"?>\n";
 721          if ($this->xslStyleSheet) $xml .= "<?xml-stylesheet href=\"".$this->xslStyleSheet."\" type=\"text/xsl\"?>\n";
 722          return $xml;
 723      }
 724      
 725      
 726      /**

 727       * Builds the feed's text.

 728       * @abstract

 729       * @return    string    the feed's complete text 

 730       */
 731  	function createFeed() {
 732      }
 733      
 734      /**

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

 736       * For example:

 737       * 

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

 739       * echo FeedCreator::_generateFilename();

 740       * 

 741       * would produce:

 742       * 

 743       * /rss/latestnews.php

 744       * latestnews.xml

 745       *

 746       * @return string the feed cache filename

 747       * @since 1.4

 748       * @access private

 749       */
 750  	function _generateFilename() {
 751          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
 752          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml";
 753      }
 754      
 755      
 756      /**

 757       * @since 1.4

 758       * @access private

 759       */
 760  	function _redirect($filename) {
 761          // attention, heavily-commented-out-area

 762          
 763          // maybe use this in addition to file time checking

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

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

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

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

 769          */
 770          
 771          // HTTP redirect, some feed readers' simple HTTP implementations don't follow it

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

 773  
 774          Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename));
 775          Header("Content-Disposition: inline; filename=".basename($filename));
 776          readfile($filename, "r");
 777          die();
 778      }
 779      
 780      /**

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

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

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

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

 785       * (web fetching, for example).

 786       * @since 1.4

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

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

 789       */
 790  	function useCached($filename="", $timeout=3600) {
 791          $this->_timeout = $timeout;
 792          if ($filename=="") {
 793              $filename = $this->_generateFilename();
 794          }
 795          if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) {
 796              $this->_redirect($filename);
 797          }
 798      }
 799      
 800      
 801      /**

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

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

 804       * @since 1.4

 805       * 

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

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

 808       */
 809  	function saveFeed($filename="", $displayContents=true) {
 810          if ($filename=="") {
 811              $filename = $this->_generateFilename();
 812          }
 813          $feedFile = fopen($filename, "w+");
 814          if ($feedFile) {
 815              fputs($feedFile,$this->createFeed());
 816              fclose($feedFile);
 817              if ($displayContents) {
 818                  $this->_redirect($filename);
 819              }
 820          } else {
 821              echo "<br /><b>Error creating feed file, please check write permissions.</b><br />";
 822          }
 823      }
 824  
 825      /**

 826       * Outputs this feed directly to the browser - for on-the-fly feed generation

 827       * @since 1.7.2-mod

 828       *

 829       * still missing: proper header output - currently you have to add it manually

 830       */
 831  	function outputFeed() {
 832          echo $this->createFeed();
 833      }
 834  
 835      
 836  }
 837  
 838  
 839  /**

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

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

 842   */
 843  class FeedDate {
 844      var $unix;
 845      
 846      /**

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

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

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

 850       */
 851  	function FeedDate($dateString="") {
 852          if ($dateString=="") $dateString = date("r");
 853          
 854          if (is_numeric($dateString)) {
 855              $this->unix = $dateString;
 856              return;
 857          }
 858          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)) {
 859              $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);
 860              $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]);
 861              if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
 862                  $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
 863              } else {
 864                  if (strlen($matches[7])==1) {
 865                      $oneHour = 3600;
 866                      $ord = ord($matches[7]);
 867                      if ($ord < ord("M")) {
 868                          $tzOffset = (ord("A") - $ord - 1) * $oneHour;
 869                      } elseif ($ord >= ord("M") AND $matches[7]!="Z") {
 870                          $tzOffset = ($ord - ord("M")) * $oneHour;
 871                      } elseif ($matches[7]=="Z") {
 872                          $tzOffset = 0;
 873                      }
 874                  }
 875                  switch ($matches[7]) {
 876                      case "UT":
 877                      case "GMT":    $tzOffset = 0;
 878                  }
 879              }
 880              $this->unix += $tzOffset;
 881              return;
 882          }
 883          if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) {
 884              $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]);
 885              if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
 886                  $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
 887              } else {
 888                  if ($matches[7]=="Z") {
 889                      $tzOffset = 0;
 890                  }
 891              }
 892              $this->unix += $tzOffset;
 893              return;
 894          }
 895          $this->unix = 0;
 896      }
 897  
 898      /**

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

 900       *

 901       * @return a date in RFC 822 format

 902       */
 903  	function rfc822() {
 904          //return gmdate("r",$this->unix);

 905          $date = gmdate("D, d M Y H:i:s", $this->unix);
 906          if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE);
 907          return $date;
 908      }
 909      
 910      /**

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

 912       *

 913       * @return a date in ISO 8601 (RFC 3339) format

 914       */
 915  	function iso8601() {
 916          $date = gmdate("Y-m-d\TH:i:sO",$this->unix);
 917          $date = substr($date,0,22) . ':' . substr($date,-2);
 918          if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date);
 919          return $date;
 920      }
 921      
 922          
 923      /**

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

 925       *

 926       * @return a date as a unix time stamp

 927       */
 928  	function unix() {
 929          return $this->unix;
 930      }
 931  }
 932  
 933  
 934  /**

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

 936   *

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

 938   * @since 1.3

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

 940   */
 941  class RSSCreator10 extends FeedCreator {
 942  
 943      /**

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

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

 946       * @return    string    the feed's complete text 

 947       */
 948  	function createFeed() {     
 949          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
 950          $feed.= $this->_createGeneratorComment();
 951          if ($this->cssStyleSheet=="") {
 952              $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css";
 953          }
 954          $feed.= $this->_createStylesheetReferences();
 955          $feed.= "<rdf:RDF\n";
 956          $feed.= "    xmlns=\"http://purl.org/rss/1.0/\"\n";
 957          $feed.= "    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; 
 958          $feed.= "    xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n";
 959          $feed.= "    xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
 960          $feed.= "    <channel rdf:about=\"".$this->syndicationURL."\">\n";
 961          $feed.= "        <title>".htmlspecialchars($this->title)."</title>\n";
 962          $feed.= "        <description>".htmlspecialchars($this->description)."</description>\n";
 963          $feed.= "        <link>".$this->link."</link>\n";
 964          if ($this->image!=null) {
 965              $feed.= "        <image rdf:resource=\"".$this->image->url."\" />\n";
 966          }
 967          $now = new FeedDate();
 968          $feed.= "       <dc:date>".htmlspecialchars($now->iso8601())."</dc:date>\n";
 969          $feed.= "        <items>\n";
 970          $feed.= "            <rdf:Seq>\n";
 971          for ($i=0;$i<count($this->items);$i++) {
 972              $feed.= "                <rdf:li rdf:resource=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
 973          }
 974          $feed.= "            </rdf:Seq>\n";
 975          $feed.= "        </items>\n";
 976          $feed.= "    </channel>\n";
 977          if ($this->image!=null) {
 978              $feed.= "    <image rdf:about=\"".$this->image->url."\">\n";
 979              $feed.= "        <title>".$this->image->title."</title>\n";
 980              $feed.= "        <link>".$this->image->link."</link>\n";
 981              $feed.= "        <url>".$this->image->url."</url>\n";
 982              $feed.= "    </image>\n";
 983          }
 984          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
 985          
 986          for ($i=0;$i<count($this->items);$i++) {
 987              $feed.= "    <item rdf:about=\"".htmlspecialchars($this->items[$i]->link)."\">\n";
 988              //$feed.= "        <dc:type>Posting</dc:type>\n";

 989              $feed.= "        <dc:format>text/html</dc:format>\n";
 990              if ($this->items[$i]->date!=null) {
 991                  $itemDate = new FeedDate($this->items[$i]->date);
 992                  $feed.= "        <dc:date>".htmlspecialchars($itemDate->iso8601())."</dc:date>\n";
 993              }
 994              if ($this->items[$i]->source!="") {
 995                  $feed.= "        <dc:source>".htmlspecialchars($this->items[$i]->source)."</dc:source>\n";
 996              }
 997              if ($this->items[$i]->author!="") {
 998                  $feed.= "        <dc:creator>".htmlspecialchars($this->items[$i]->author)."</dc:creator>\n";
 999              }
1000              $feed.= "        <title>".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")))."</title>\n";
1001              $feed.= "        <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
1002              $feed.= "        <description>".htmlspecialchars($this->items[$i]->description)."</description>\n";
1003              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1004              $feed.= "    </item>\n";
1005          }
1006          $feed.= "</rdf:RDF>\n";
1007          return $feed;
1008      }
1009  }
1010  
1011  
1012  
1013  /**

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

1015   *

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

1017   * @since 1.3

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

1019   */
1020  class RSSCreator091 extends FeedCreator {
1021  
1022      /**

1023       * Stores this RSS feed's version number.

1024       * @access private

1025       */
1026      var $RSSVersion;
1027  
1028  	function RSSCreator091() {
1029          $this->_setRSSVersion("0.91");
1030          $this->contentType = "application/rss+xml";
1031      }
1032      
1033      /**

1034       * Sets this RSS feed's version number.

1035       * @access private

1036       */
1037  	function _setRSSVersion($version) {
1038          $this->RSSVersion = $version;
1039      }
1040  
1041      /**

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

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

1044       * @return    string    the feed's complete text 

1045       */
1046  	function createFeed() {
1047          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1048          $feed.= $this->_createGeneratorComment();
1049          $feed.= $this->_createStylesheetReferences();
1050          $feed.= "<rss version=\"".$this->RSSVersion."\">\n"; 
1051          $feed.= "    <channel>\n";
1052          $feed.= "        <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
1053          $this->descriptionTruncSize = 500;
1054          $feed.= "        <description>".$this->getDescription()."</description>\n";
1055          $feed.= "        <link>".$this->link."</link>\n";
1056          $now = new FeedDate();
1057          $feed.= "        <lastBuildDate>".htmlspecialchars($now->rfc822())."</lastBuildDate>\n";
1058          $feed.= "        <generator>".FEEDCREATOR_VERSION."</generator>\n";
1059  
1060          if ($this->image!=null) {
1061              $feed.= "        <image>\n";
1062              $feed.= "            <url>".$this->image->url."</url>\n"; 
1063              $feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."</title>\n"; 
1064              $feed.= "            <link>".$this->image->link."</link>\n";
1065              if ($this->image->width!="") {
1066                  $feed.= "            <width>".$this->image->width."</width>\n";
1067              }
1068              if ($this->image->height!="") {
1069                  $feed.= "            <height>".$this->image->height."</height>\n";
1070              }
1071              if ($this->image->description!="") {
1072                  $feed.= "            <description>".$this->image->getDescription()."</description>\n";
1073              }
1074              $feed.= "        </image>\n";
1075          }
1076          if ($this->language!="") {
1077              $feed.= "        <language>".$this->language."</language>\n";
1078          }
1079          if ($this->copyright!="") {
1080              $feed.= "        <copyright>".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."</copyright>\n";
1081          }
1082          if ($this->editor!="") {
1083              $feed.= "        <managingEditor>".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."</managingEditor>\n";
1084          }
1085          if ($this->webmaster!="") {
1086              $feed.= "        <webMaster>".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."</webMaster>\n";
1087          }
1088          if ($this->pubDate!="") {
1089              $pubDate = new FeedDate($this->pubDate);
1090              $feed.= "        <pubDate>".htmlspecialchars($pubDate->rfc822())."</pubDate>\n";
1091          }
1092          if ($this->category!="") {
1093              $feed.= "        <category>".htmlspecialchars($this->category)."</category>\n";
1094          }
1095          if ($this->docs!="") {
1096              $feed.= "        <docs>".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."</docs>\n";
1097          }
1098          if ($this->ttl!="") {
1099              $feed.= "        <ttl>".htmlspecialchars($this->ttl)."</ttl>\n";
1100          }
1101          if ($this->rating!="") {
1102              $feed.= "        <rating>".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."</rating>\n";
1103          }
1104          if ($this->skipHours!="") {
1105              $feed.= "        <skipHours>".htmlspecialchars($this->skipHours)."</skipHours>\n";
1106          }
1107          if ($this->skipDays!="") {
1108              $feed.= "        <skipDays>".htmlspecialchars($this->skipDays)."</skipDays>\n";
1109          }
1110          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
1111  
1112          for ($i=0;$i<count($this->items);$i++) {
1113              $feed.= "        <item>\n";
1114              $feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
1115              $feed.= "            <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
1116              $feed.= "            <description>".$this->items[$i]->getDescription()."</description>\n";
1117              
1118              if ($this->items[$i]->author!="") {
1119                  $feed.= "            <author>".htmlspecialchars($this->items[$i]->author)."</author>\n";
1120              }
1121              /*

1122              // on hold

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

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

1125              }

1126              */
1127              if ($this->items[$i]->category!="") {
1128                  $feed.= "            <category>".htmlspecialchars($this->items[$i]->category)."</category>\n";
1129              }
1130              if ($this->items[$i]->comments!="") {
1131                  $feed.= "            <comments>".htmlspecialchars($this->items[$i]->comments)."</comments>\n";
1132              }
1133              if ($this->items[$i]->date!="") {
1134              $itemDate = new FeedDate($this->items[$i]->date);
1135                  $feed.= "            <pubDate>".htmlspecialchars($itemDate->rfc822())."</pubDate>\n";
1136              }
1137              if ($this->items[$i]->guid!="") {
1138                  $feed.= "            <guid>".htmlspecialchars($this->items[$i]->guid)."</guid>\n";
1139              }
1140              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1141              
1142              if ($this->RSSVersion == "2.0" && $this->items[$i]->enclosure != NULL)
1143                  {
1144                                  $feed.= "            <enclosure url=\"";
1145                                  $feed.= $this->items[$i]->enclosure->url;
1146                                  $feed.= "\" length=\"";
1147                                  $feed.= $this->items[$i]->enclosure->length;
1148                                  $feed.= "\" type=\"";
1149                                  $feed.= $this->items[$i]->enclosure->type;
1150                                  $feed.= "\"/>\n";
1151                          }
1152                  
1153          
1154          
1155              $feed.= "        </item>\n";
1156          }
1157          
1158          $feed.= "    </channel>\n";
1159          $feed.= "</rss>\n";
1160          return $feed;
1161      }
1162  }
1163  
1164  
1165  
1166  /**

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

1168   *

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

1170   * @since 1.3

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

1172   */
1173  class RSSCreator20 extends RSSCreator091 {
1174  
1175      function RSSCreator20() {
1176          parent::_setRSSVersion("2.0");
1177      }
1178      
1179  }
1180  
1181  
1182  /**

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

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

1185   *

1186   * @deprecated

1187   * @since 1.3

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

1189   */
1190  class PIECreator01 extends FeedCreator {
1191      
1192  	function PIECreator01() {
1193          $this->encoding = "utf-8";
1194      }
1195      
1196  	function createFeed() {
1197          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1198          $feed.= $this->_createStylesheetReferences();
1199          $feed.= "<feed version=\"0.1\" xmlns=\"http://example.com/newformat#\">\n"; 
1200          $feed.= "    <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
1201          $this->truncSize = 500;
1202          $feed.= "    <subtitle>".$this->getDescription()."</subtitle>\n";
1203          $feed.= "    <link>".$this->link."</link>\n";
1204          for ($i=0;$i<count($this->items);$i++) {
1205              $feed.= "    <entry>\n";
1206              $feed.= "        <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
1207              $feed.= "        <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
1208              $itemDate = new FeedDate($this->items[$i]->date);
1209              $feed.= "        <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1210              $feed.= "        <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1211              $feed.= "        <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1212              $feed.= "        <id>".htmlspecialchars($this->items[$i]->guid)."</id>\n";
1213              if ($this->items[$i]->author!="") {
1214                  $feed.= "        <author>\n";
1215                  $feed.= "            <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1216                  if ($this->items[$i]->authorEmail!="") {
1217                      $feed.= "            <email>".$this->items[$i]->authorEmail."</email>\n";
1218                  }
1219                  $feed.="        </author>\n";
1220              }
1221              $feed.= "        <content type=\"text/html\" xml:lang=\"en-us\">\n";
1222              $feed.= "            <div xmlns=\"http://www.w3.org/1999/xhtml\">".$this->items[$i]->getDescription()."</div>\n";
1223              $feed.= "        </content>\n";
1224              $feed.= "    </entry>\n";
1225          }
1226          $feed.= "</feed>\n";
1227          return $feed;
1228      }
1229  }
1230  
1231  /**

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

1233   * as in http://www.atomenabled.org/developers/syndication/atom-format-spec.php

1234   * Please note that just by using AtomCreator10 you won't automatically

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

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

1237   *

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

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

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

1241   * AtomCreator10::additionalElements.

1242   *

1243   * @see FeedCreator#additionalElements

1244   * @since 1.7.2-mod (modified)

1245   * @author Mohammad Hafiz Ismail (mypapit@gmail.com)

1246   */
1247   class AtomCreator10 extends FeedCreator {
1248   
1249  	function AtomCreator10() {
1250          $this->contentType = "application/atom+xml";
1251          $this->encoding = "utf-8";
1252      }
1253  
1254  	function createFeed() {
1255          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1256          $feed.= $this->_createGeneratorComment();
1257          $feed.= $this->_createStylesheetReferences();
1258          $feed.= "<feed xmlns=\"http://www.w3.org/2005/Atom\"";
1259          if ($this->language!="") {
1260              $feed.= " xml:lang=\"".$this->language."\"";
1261          }
1262          $feed.= ">\n"; 
1263          $feed.= "    <title>".htmlspecialchars($this->title)."</title>\n";
1264          $feed.= "    <subtitle>".htmlspecialchars($this->description)."</subtitle>\n";
1265          $feed.= "    <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link)."\"/>\n";
1266          $feed.= "    <id>".htmlspecialchars($this->link)."</id>\n";
1267          $now = new FeedDate();
1268          $feed.= "    <updated>".htmlspecialchars($now->iso8601())."</updated>\n";
1269          if ($this->editor!="") {
1270              $feed.= "    <author>\n";
1271              $feed.= "        <name>".$this->editor."</name>\n";
1272              if ($this->editorEmail!="") {
1273                  $feed.= "        <email>".$this->editorEmail."</email>\n";
1274              }
1275              $feed.= "    </author>\n";
1276          }
1277          $feed.= "    <generator>".FEEDCREATOR_VERSION."</generator>\n";
1278          $feed.= "<link rel=\"self\" type=\"application/atom+xml\" href=\"". $this->syndicationURL . "\" />\n";
1279          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
1280          for ($i=0;$i<count($this->items);$i++) {
1281              $feed.= "    <entry>\n";
1282              $feed.= "        <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n";
1283              $feed.= "        <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
1284              if ($this->items[$i]->date=="") {
1285                  $this->items[$i]->date = time();
1286              }
1287              $itemDate = new FeedDate($this->items[$i]->date);
1288              $feed.= "        <published>".htmlspecialchars($itemDate->iso8601())."</published>\n";
1289              $feed.= "        <updated>".htmlspecialchars($itemDate->iso8601())."</updated>\n";
1290              $feed.= "        <id>".htmlspecialchars($this->items[$i]->link)."</id>\n";
1291              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1292              if ($this->items[$i]->author!="") {
1293                  $feed.= "        <author>\n";
1294                  $feed.= "            <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1295                  $feed.= "        </author>\n";
1296              }
1297              if ($this->items[$i]->description!="") {
1298                  $feed.= "        <summary>".htmlspecialchars($this->items[$i]->description)."</summary>\n";
1299              }
1300              if ($this->items[$i]->enclosure != NULL) {
1301              $feed.="        <link rel=\"enclosure\" href=\"". $this->items[$i]->enclosure->url ."\" type=\"". $this->items[$i]->enclosure->type."\"  length=\"". $this->items[$i]->enclosure->length . "\" />\n";
1302              }
1303              $feed.= "    </entry>\n";
1304          }
1305          $feed.= "</feed>\n";
1306          return $feed;
1307      }
1308  
1309      
1310  }
1311   
1312   
1313  /**

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

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

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

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

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

1319   *

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

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

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

1323   * AtomCreator03::additionalElements.

1324   *

1325   * @see FeedCreator#additionalElements

1326   * @since 1.6

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

1328   */
1329  class AtomCreator03 extends FeedCreator {
1330  
1331  	function AtomCreator03() {
1332          $this->contentType = "application/atom+xml";
1333          $this->encoding = "utf-8";
1334      }
1335      
1336  	function createFeed() {
1337          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1338          $feed.= $this->_createGeneratorComment();
1339          $feed.= $this->_createStylesheetReferences();
1340          $feed.= "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\"";
1341          if ($this->language!="") {
1342              $feed.= " xml:lang=\"".$this->language."\"";
1343          }
1344          $feed.= ">\n"; 
1345          $feed.= "    <title>".htmlspecialchars($this->title)."</title>\n";
1346          $feed.= "    <tagline>".htmlspecialchars($this->description)."</tagline>\n";
1347          $feed.= "    <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link)."\"/>\n";
1348          $feed.= "    <id>".htmlspecialchars($this->link)."</id>\n";
1349          $now = new FeedDate();
1350          $feed.= "    <modified>".htmlspecialchars($now->iso8601())."</modified>\n";
1351          if ($this->editor!="") {
1352              $feed.= "    <author>\n";
1353              $feed.= "        <name>".$this->editor."</name>\n";
1354              if ($this->editorEmail!="") {
1355                  $feed.= "        <email>".$this->editorEmail."</email>\n";
1356              }
1357              $feed.= "    </author>\n";
1358          }
1359          $feed.= "    <generator>".FEEDCREATOR_VERSION."</generator>\n";
1360          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
1361          for ($i=0;$i<count($this->items);$i++) {
1362              $feed.= "    <entry>\n";
1363              $feed.= "        <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n";
1364              $feed.= "        <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
1365              if ($this->items[$i]->date=="") {
1366                  $this->items[$i]->date = time();
1367              }
1368              $itemDate = new FeedDate($this->items[$i]->date);
1369              $feed.= "        <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1370              $feed.= "        <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1371              $feed.= "        <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1372              $feed.= "        <id>".htmlspecialchars($this->items[$i]->link)."</id>\n";
1373              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1374              if ($this->items[$i]->author!="") {
1375                  $feed.= "        <author>\n";
1376                  $feed.= "            <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1377                  $feed.= "        </author>\n";
1378              }
1379              if ($this->items[$i]->description!="") {
1380                  $feed.= "        <summary>".htmlspecialchars($this->items[$i]->description)."</summary>\n";
1381              }
1382              $feed.= "    </entry>\n";
1383          }
1384          $feed.= "</feed>\n";
1385          return $feed;
1386      }
1387  }
1388  
1389  
1390  /**

1391   * MBOXCreator is a FeedCreator that implements the mbox format

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

1393   *

1394   * @since 1.3

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

1396   */
1397  class MBOXCreator extends FeedCreator {
1398  
1399  	function MBOXCreator() {
1400          $this->contentType = "text/plain";
1401          $this->encoding = "ISO-8859-15";
1402      }
1403      
1404  	function qp_enc($input = "", $line_max = 76) { 
1405          $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); 
1406          $lines = preg_split("/(?:\r\n|\r|\n)/", $input); 
1407          $eol = "\r\n"; 
1408          $escape = "="; 
1409          $output = ""; 
1410          while( list(, $line) = each($lines) ) { 
1411              //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary 

1412              $linlen = strlen($line); 
1413              $newline = ""; 
1414              for($i = 0; $i < $linlen; $i++) { 
1415                  $c = substr($line, $i, 1); 
1416                  $dec = ord($c); 
1417                  if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only 
1418                      $c = "=20"; 
1419                  } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required 
1420                      $h2 = floor($dec/16); $h1 = floor($dec%16); 
1421                      $c = $escape.$hex["$h2"].$hex["$h1"]; 
1422                  } 
1423                  if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted 
1424                      $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay 

1425                      $newline = ""; 
1426                  } 
1427                  $newline .= $c; 
1428              } // end of for 

1429              $output .= $newline.$eol; 
1430          } 
1431          return trim($output); 
1432      }
1433      
1434  
1435      /**

1436       * Builds the MBOX contents.

1437       * @return    string    the feed's complete text 

1438       */
1439  	function createFeed() {
1440          for ($i=0;$i<count($this->items);$i++) {
1441              if ($this->items[$i]->author!="") {
1442                  $from = $this->items[$i]->author;
1443              } else {
1444                  $from = $this->title;
1445              }
1446              $itemDate = new FeedDate($this->items[$i]->date);
1447              $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n";
1448              $feed.= "Content-Type: text/plain;\n";
1449              $feed.= "    charset=\"".$this->encoding."\"\n";
1450              $feed.= "Content-Transfer-Encoding: quoted-printable\n";
1451              $feed.= "Content-Type: text/plain\n";
1452              $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n";
1453              $feed.= "Date: ".$itemDate->rfc822()."\n";
1454              $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n";
1455              $feed.= "\n";
1456              $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description));
1457              $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body);
1458              $feed.= "\n";
1459              $feed.= "\n";
1460          }
1461          return $feed;
1462      }
1463      
1464      /**

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

1466       * @return string the feed cache filename

1467       * @since 1.4

1468       * @access private

1469       */
1470  	function _generateFilename() {
1471          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1472          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox";
1473      }
1474  }
1475  
1476  
1477  /**

1478   * OPMLCreator is a FeedCreator that implements OPML 1.0.

1479   * 

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

1481   * @author Dirk Clemens, Kai Blankenhorn

1482   * @since 1.5

1483   */
1484  class OPMLCreator extends FeedCreator {
1485  
1486  	function OPMLCreator() {
1487          $this->encoding = "utf-8";
1488      }
1489      
1490  	function createFeed() {     
1491          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1492          $feed.= $this->_createGeneratorComment();
1493          $feed.= $this->_createStylesheetReferences();
1494          $feed.= "<opml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
1495          $feed.= "    <head>\n";
1496          $feed.= "        <title>".htmlspecialchars($this->title)."</title>\n";
1497          if ($this->pubDate!="") {
1498              $date = new FeedDate($this->pubDate);
1499              $feed.= "         <dateCreated>".$date->rfc822()."</dateCreated>\n";
1500          }
1501          if ($this->lastBuildDate!="") {
1502              $date = new FeedDate($this->lastBuildDate);
1503              $feed.= "         <dateModified>".$date->rfc822()."</dateModified>\n";
1504          }
1505          if ($this->editor!="") {
1506              $feed.= "         <ownerName>".$this->editor."</ownerName>\n";
1507          }
1508          if ($this->editorEmail!="") {
1509              $feed.= "         <ownerEmail>".$this->editorEmail."</ownerEmail>\n";
1510          }
1511          $feed.= "    </head>\n";
1512          $feed.= "    <body>\n";
1513          for ($i=0;$i<count($this->items);$i++) {
1514              $feed.= "    <outline type=\"rss\" ";
1515              $title = htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")));
1516              $feed.= " title=\"".$title."\"";
1517              $feed.= " text=\"".$title."\"";
1518              //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\"";

1519              $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\"";
1520              $feed.= "/>\n";
1521          }
1522          $feed.= "    </body>\n";
1523          $feed.= "</opml>\n";
1524          return $feed;
1525      }
1526  }
1527  
1528  
1529  
1530  /**

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

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

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

1534   * as the source for an IFrame.

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

1536   * using CSS. 

1537   *

1538   * @author Pascal Van Hecke

1539   * @since 1.7

1540   */
1541  class HTMLCreator extends FeedCreator {
1542  
1543      var $contentType = "text/html";
1544      
1545      /**

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

1547       */
1548      var $header;
1549      
1550      /**

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

1552       */
1553      var $footer ;
1554      
1555      /**

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

1557       * case of multiple entries.

1558       */
1559      var $separator;
1560      
1561      /**

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

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

1564       */
1565      var $stylePrefix;
1566      
1567      /**

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

1569       */
1570      var $openInNewWindow = true;
1571      
1572      var $imageAlign ="right";
1573      
1574      /**

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

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

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

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

1579       * in the function createFeed().

1580       */
1581      var $stylelessOutput ="";
1582  
1583      /**

1584       * Writes the HTML.

1585       * @return    string    the scripts's complete text 

1586       */
1587  	function createFeed() {
1588          // if there is styleless output, use the content of this variable and ignore the rest

1589          if ($this->stylelessOutput!="") {
1590              return $this->stylelessOutput;
1591          }
1592          
1593          //if no stylePrefix is set, generate it yourself depending on the script name

1594          if ($this->stylePrefix=="") {
1595              $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_";
1596          }
1597  
1598          //set an openInNewWindow_token_to be inserted or not

1599          if ($this->openInNewWindow) {
1600              $targetInsert = " target='_blank'";
1601          }
1602          
1603          // use this array to put the lines in and implode later with "document.write" javascript

1604          $feedArray = array();
1605          if ($this->image!=null) {
1606              $imageStr = "<a href='".$this->image->link."'".$targetInsert.">".
1607                              "<img src='".$this->image->url."' border='0' alt='".
1608                              FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
1609                              "' align='".$this->imageAlign."' ";
1610              if ($this->image->width) {
1611                  $imageStr .=" width='".$this->image->width. "' ";
1612              }
1613              if ($this->image->height) {
1614                  $imageStr .=" height='".$this->image->height."' ";
1615              }
1616              $imageStr .="/></a>";
1617              $feedArray[] = $imageStr;
1618          }
1619          
1620          if ($this->title) {
1621              $feedArray[] = "<div class='".$this->stylePrefix."title'><a href='".$this->link."' ".$targetInsert." class='".$this->stylePrefix."title'>".
1622                  FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</a></div>";
1623          }
1624          if ($this->getDescription()) {
1625              $feedArray[] = "<div class='".$this->stylePrefix."description'>".
1626                  str_replace("]]>", "", str_replace("<![CDATA[", "", $this->getDescription())).
1627                  "</div>";
1628          }
1629          
1630          if ($this->header) {
1631              $feedArray[] = "<div class='".$this->stylePrefix."header'>".$this->header."</div>";
1632          }
1633          
1634          for ($i=0;$i<count($this->items);$i++) {
1635              if ($this->separator and $i > 0) {
1636                  $feedArray[] = "<div class='".$this->stylePrefix."separator'>".$this->separator."</div>";
1637              }
1638              
1639              if ($this->items[$i]->title) {
1640                  if ($this->items[$i]->link) {
1641                      $feedArray[] = 
1642                          "<div class='".$this->stylePrefix."item_title'><a href='".$this->items[$i]->link."' class='".$this->stylePrefix.
1643                          "item_title'".$targetInsert.">".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
1644                          "</a></div>";
1645                  } else {
1646                      $feedArray[] = 
1647                          "<div class='".$this->stylePrefix."item_title'>".
1648                          FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
1649                          "</div>";
1650                  }
1651              }
1652              if ($this->items[$i]->getDescription()) {
1653                  $feedArray[] = 
1654                  "<div class='".$this->stylePrefix."item_description'>".
1655                      str_replace("]]>", "", str_replace("<![CDATA[", "", $this->items[$i]->getDescription())).
1656                      "</div>";
1657              }
1658          }
1659          if ($this->footer) {
1660              $feedArray[] = "<div class='".$this->stylePrefix."footer'>".$this->footer."</div>";
1661          }
1662          
1663          $feed= "".join($feedArray, "\r\n");
1664          return $feed;
1665      }
1666      
1667      /**

1668       * Overrrides parent to produce .html extensions

1669       *

1670       * @return string the feed cache filename

1671       * @since 1.4

1672       * @access private

1673       */
1674  	function _generateFilename() {
1675          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1676          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html";
1677      }
1678  }    
1679  
1680  
1681  /**

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

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

1684   *

1685   * @author Pascal Van Hecke

1686   */
1687  class JSCreator extends HTMLCreator {
1688      var $contentType = "text/javascript";
1689      
1690      /**

1691       * writes the javascript

1692       * @return    string    the scripts's complete text 

1693       */
1694  	function createFeed() 
1695      {
1696          $feed = parent::createFeed();
1697          $feedArray = explode("\n",$feed);
1698          
1699          $jsFeed = "";
1700          foreach ($feedArray as $value) {
1701              $jsFeed .= "document.write('".trim(addslashes($value))."');\n";
1702          }
1703          return $jsFeed;
1704      }
1705      
1706      /**

1707       * Overrrides parent to produce .js extensions

1708       *

1709       * @return string the feed cache filename

1710       * @since 1.4

1711       * @access private

1712       */
1713  	function _generateFilename() {
1714          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1715          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js";
1716      }
1717      
1718  }    
1719  
1720  
1721  
1722  /*** TEST SCRIPT *********************************************************

1723  

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

1725  

1726  $rss = new UniversalFeedCreator(); 

1727  $rss->useCached(); 

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

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

1730  

1731  //optional

1732  //$rss->descriptionTruncSize = 500;

1733  //$rss->descriptionHtmlSyndicated = true;

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

1735  

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

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

1738  

1739  $image = new FeedImage(); 

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

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

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

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

1744  

1745  //optional

1746  $image->descriptionTruncSize = 500;

1747  $image->descriptionHtmlSyndicated = true;

1748  

1749  $rss->image = $image; 

1750  

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

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

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

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

1755      $item = new FeedItem(); 

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

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

1758      $item->description = "<b>description in </b><br/>HTML"; 

1759      

1760      //optional

1761      //item->descriptionTruncSize = 500;

1762      $item->descriptionHtmlSyndicated = true;

1763      

1764      $item->date = time(); 

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

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

1767       

1768      $rss->addItem($item); 

1769  //} 

1770  

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

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

1773  

1774  

1775  

1776  ***************************************************************************/
1777  
1778  ?>

title

Description

title

Description

title

Description

title

title

Body