[ Index ]

PHP Cross Reference of phpwcms V1.4.3 _r380 (23.11.09)

title

Body

[close]

/include/inc_ext/feedcreator/ -> 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  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("RSS2.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  define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2 enhanced");
 189  
 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      var $updateDate;
 225      
 226      /**
 227       * Add <enclosure> element tag RSS 2.0
 228       * modified by : Mohammad Hafiz bin Ismail (mypapit@gmail.com)
 229       *
 230       *
 231       * display :
 232       * <enclosure length="17691" url="http://something.com/picture.jpg" type="image/jpeg" />
 233       * 
 234       */
 235      var $enclosure;
 236      
 237      /**
 238       * Any additional elements to include as an assiciated array. All $key => $value pairs
 239       * will be included unencoded in the feed item in the form
 240       *     <$key>$value</$key>
 241       * Again: No encoding will be used! This means you can invalidate or enhance the feed
 242       * if $value contains markup. This may be abused to embed tags not implemented by
 243       * the FeedCreator class used.
 244       */
 245      var $additionalElements = Array();
 246  
 247      // on hold
 248      // var $source;
 249  }
 250  
 251  class EnclosureItem extends HtmlDescribable {
 252      /*
 253      * 
 254      * core variables
 255      *
 256      **/
 257      var $url,$length,$type;
 258      
 259      /*
 260      * For use with another extension like Yahoo mRSS
 261      * Warning :
 262      * These variables might not show up in 
 263      * later release / not finalize yet!
 264      *
 265      */
 266      var $width, $height, $title, $description, $keywords, $thumburl;
 267      
 268      var $additionalElements = Array();
 269  
 270  }
 271  
 272  
 273  /**
 274   * An FeedImage may be added to a FeedCreator feed.
 275   * @author Kai Blankenhorn <kaib@bitfolge.de>
 276   * @since 1.3
 277   */
 278  class FeedImage extends HtmlDescribable {
 279      /**
 280       * Mandatory attributes of an image.
 281       */
 282      var $title, $url, $link;
 283      
 284      /**
 285       * Optional attributes of an image.
 286       */
 287      var $width, $height, $description;
 288  }
 289  
 290  
 291  
 292  /**
 293   * An HtmlDescribable is an item within a feed that can have a description that may
 294   * include HTML markup.
 295   */
 296  class HtmlDescribable {
 297      /**
 298       * Indicates whether the description field should be rendered in HTML.
 299       */
 300      var $descriptionHtmlSyndicated;
 301      
 302      /**
 303       * Indicates whether and to how many characters a description should be truncated.
 304       */
 305      var $descriptionTruncSize;
 306      
 307      /**
 308       * Returns a formatted description field, depending on descriptionHtmlSyndicated and
 309       * $descriptionTruncSize properties
 310       * @return    string    the formatted description  
 311       */
 312  	function getDescription() {
 313          $descriptionField = new FeedHtmlField($this->description);
 314          $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated;
 315          $descriptionField->truncSize = $this->descriptionTruncSize;
 316          return $descriptionField->output();
 317      }
 318  
 319  }
 320  
 321  
 322  
 323  /**
 324   * An FeedHtmlField describes and generates
 325   * a feed, item or image html field (probably a description). Output is 
 326   * generated based on $truncSize, $syndicateHtml properties.
 327   * @author Pascal Van Hecke <feedcreator.class.php@vanhecke.info>
 328   * @version 1.6
 329   */
 330  class FeedHtmlField {
 331      /**
 332       * Mandatory attributes of a FeedHtmlField.
 333       */
 334      var $rawFieldContent;
 335      
 336      /**
 337       * Optional attributes of a FeedHtmlField.
 338       * 
 339       */
 340      var $truncSize, $syndicateHtml;
 341      
 342      /**
 343       * Creates a new instance of FeedHtmlField.
 344       * @param  $string: if given, sets the rawFieldContent property
 345       */
 346  	function FeedHtmlField($parFieldContent) {
 347          if ($parFieldContent) {
 348              $this->rawFieldContent = $parFieldContent;
 349          }
 350      }
 351          
 352          
 353      /**
 354       * Creates the right output, depending on $truncSize, $syndicateHtml properties.
 355       * @return string    the formatted field
 356       */
 357  	function output() {
 358          // when field available and syndicated in html we assume 
 359          // - valid html in $rawFieldContent and we enclose in CDATA tags
 360          // - no truncation (truncating risks producing invalid html)
 361          if (!$this->rawFieldContent) {
 362              $result = "";
 363          }    elseif ($this->syndicateHtml) {
 364              $result = "<![CDATA[".$this->rawFieldContent."]]>";
 365          } else {
 366              if ($this->truncSize and is_int($this->truncSize)) {
 367                  $result = FeedCreator::iTrunc(html_specialchars($this->rawFieldContent),$this->truncSize);
 368              } else {
 369                  $result = html_specialchars($this->rawFieldContent);
 370              }
 371          }
 372          return $result;
 373      }
 374  
 375  }
 376  
 377  
 378  
 379  /**
 380   * UniversalFeedCreator lets you choose during runtime which
 381   * format to build.
 382   * For general usage of a feed class, see the FeedCreator class
 383   * below or the example above.
 384   *
 385   * @since 1.3
 386   * @author Kai Blankenhorn <kaib@bitfolge.de>
 387   */
 388  class UniversalFeedCreator extends FeedCreator {
 389      var $_feed;
 390      
 391  	function _setMIME($format) {
 392          switch (strtoupper($format)) {
 393              
 394              case "2.0":
 395                  // fall through
 396              case "RSS2.0":
 397                  header('Content-type: text/xml', true);
 398                  break;
 399              
 400              case "1.0":
 401                  // fall through
 402              case "RSS1.0":
 403                  header('Content-type: text/xml', true);
 404                  break;
 405              
 406              case "PIE0.1":
 407                  header('Content-type: text/xml', true);
 408                  break;
 409              
 410              case "MBOX":
 411                  header('Content-type: text/plain', true);
 412                  break;
 413              
 414              case "OPML":
 415                  header('Content-type: text/xml', true);
 416                  break;
 417                  
 418              case "ATOM":
 419                  // fall through: always the latest ATOM version
 420              case "ATOM1.0":
 421                  header('Content-type: application/xml', true);
 422                  break;
 423                  
 424              case "ATOM0.3":
 425                  header('Content-type: application/xml', true);
 426                  break;
 427      
 428                  
 429              case "HTML":
 430                  header('Content-type: text/html', true);
 431                  break;
 432              
 433              case "JS":
 434                  // fall through
 435              case "JAVASCRIPT":
 436                  header('Content-type: text/javascript', true);
 437                  break;
 438  
 439              default:
 440              case "0.91":
 441                  // fall through
 442              case "RSS0.91":
 443                  header('Content-type: text/xml', true);
 444                  break;
 445          }
 446      }
 447      
 448  	function _setFormat($format) {
 449          switch (strtoupper($format)) {
 450              
 451              case "2.0":
 452                  // fall through
 453              case "RSS2.0":
 454                  $this->_feed = new RSSCreator20();
 455                  break;
 456              
 457              case "1.0":
 458                  // fall through
 459              case "RSS1.0":
 460                  $this->_feed = new RSSCreator10();
 461                  break;
 462              
 463              case "0.91":
 464                  // fall through
 465              case "RSS0.91":
 466                  $this->_feed = new RSSCreator091();
 467                  break;
 468              
 469              case "PIE0.1":
 470                  $this->_feed = new PIECreator01();
 471                  break;
 472              
 473              case "MBOX":
 474                  $this->_feed = new MBOXCreator();
 475                  break;
 476              
 477              case "OPML":
 478                  $this->_feed = new OPMLCreator();
 479                  break;
 480                  
 481              case "ATOM":
 482                  // fall through: always the latest ATOM version
 483              case "ATOM1.0":
 484                  $this->_feed = new AtomCreator10();
 485                  break;
 486              
 487                  
 488              case "ATOM0.3":
 489                  $this->_feed = new AtomCreator03();
 490                  break;
 491                  
 492              case "HTML":
 493                  $this->_feed = new HTMLCreator();
 494                  break;
 495              
 496              case "JS":
 497                  // fall through
 498              case "JAVASCRIPT":
 499                  $this->_feed = new JSCreator();
 500                  break;
 501              
 502              default:
 503                  $this->_feed = new RSSCreator091();
 504                  break;
 505          }
 506          
 507          $vars = get_object_vars($this);
 508          
 509          foreach ($vars as $key => $value) {
 510              // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself
 511              //if (!in_array($key, array("_feed", "contentType", "encoding"))) {
 512              if (!in_array($key, array("_feed", "contentType"))) {
 513                  $this->_feed->{$key} = $this->{$key};
 514              }
 515          }
 516      }
 517      
 518      /**
 519       * Creates a syndication feed based on the items previously added.
 520       *
 521       * @see        FeedCreator::addItem()
 522       * @param    string    format    format the feed should comply to. Valid values are:
 523       *            "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS"
 524       * @return    string    the contents of the feed.
 525       */
 526  	function createFeed($format = "RSS0.91") {
 527          $this->_setFormat($format);
 528          return $this->_feed->createFeed();
 529      }
 530      
 531      
 532      
 533      /**
 534       * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect
 535       * header may be sent to redirect the use to the newly created file.
 536       * @since 1.4
 537       * 
 538       * @param    string    format    format the feed should comply to. Valid values are:
 539       *            "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS"
 540       * @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()).
 541       * @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.
 542       */
 543  	function saveFeed($format="RSS0.91", $filename="", $displayContents=true) {
 544          $this->_setFormat($format);
 545          $this->_feed->saveFeed($filename, $displayContents);
 546      }
 547  
 548  
 549     /**
 550      * Turns on caching and checks if there is a recent version of this feed in the cache.
 551      * If there is, an HTTP redirect header is sent.
 552      * To effectively use caching, you should create the FeedCreator object and call this method
 553      * before anything else, especially before you do the time consuming task to build the feed
 554      * (web fetching, for example).
 555      *
 556      * @param   string   format   format the feed should comply to. Valid values are:
 557      *       "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3".
 558      * @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()).
 559      * @param timeout int      optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
 560      */
 561     function useCached($format="RSS0.91", $filename="", $timeout=3600) {
 562        $this->_setFormat($format);
 563        $this->_feed->useCached($filename, $timeout);
 564     }
 565  
 566     
 567     /**
 568      * Outputs feed to the browser - needed for on-the-fly feed generation (like it is done in WordPress, etc.)
 569      *
 570      * @param    format    string    format the feed should comply to. Valid values are:
 571      *                             "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3".
 572      */
 573     function outputFeed($format='RSS0.91') {
 574          $this->_setFormat($format);
 575          $this->_setMIME($format);
 576          $this->_feed->outputFeed();
 577     }
 578     
 579     
 580  }
 581  
 582  
 583  /**
 584   * FeedCreator is the abstract base implementation for concrete
 585   * implementations that implement a specific format of syndication.
 586   *
 587   * @abstract
 588   * @author Kai Blankenhorn <kaib@bitfolge.de>
 589   * @since 1.4
 590   */
 591  class FeedCreator extends HtmlDescribable {
 592  
 593      /**
 594       * Mandatory attributes of a feed.
 595       */
 596      var $title, $description, $link;
 597      
 598      
 599      /**
 600       * Optional attributes of a feed.
 601       */
 602      var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays;
 603  
 604      /**
 605      * The url of the external xsl stylesheet used to format the naked rss feed.
 606      * Ignored in the output when empty.
 607      */
 608      var $xslStyleSheet = "";
 609      
 610      
 611      /**
 612       * @access private
 613       */
 614      var $items = Array();
 615       
 616      
 617      /**
 618       * This feed's MIME content type.
 619       * @since 1.4
 620       * @access private
 621       */
 622      var $contentType = "application/xml";
 623      
 624      
 625      /**
 626       * This feed's character encoding.
 627       * @since 1.6.1
 628       **/
 629      var $encoding = FEED_ENCODING; //"ISO-8859-1"
 630      
 631      
 632      /**
 633       * Any additional elements to include as an assiciated array. All $key => $value pairs
 634       * will be included unencoded in the feed in the form
 635       *     <$key>$value</$key>
 636       * Again: No encoding will be used! This means you can invalidate or enhance the feed
 637       * if $value contains markup. This may be abused to embed tags not implemented by
 638       * the FeedCreator class used.
 639       */
 640      var $additionalElements = Array();
 641     
 642      
 643      /**
 644       * Adds an FeedItem to the feed.
 645       *
 646       * @param object FeedItem $item The FeedItem to add to the feed.
 647       * @access public
 648       */
 649  	function addItem($item) {
 650          $this->items[] = $item;
 651      }
 652      
 653      
 654      /**
 655       * Truncates a string to a certain length at the most sensible point.
 656       * First, if there's a '.' character near the end of the string, the string is truncated after this character.
 657       * If there is no '.', the string is truncated after the last ' ' character.
 658       * If the string is truncated, " ..." is appended.
 659       * If the string is already shorter than $length, it is returned unchanged.
 660       * 
 661       * @static
 662       * @param string    string A string to be truncated.
 663       * @param int        length the maximum length the string should be truncated to
 664       * @return string    the truncated string
 665       */
 666  	function iTrunc($string, $length) {
 667          if (strlen($string)<=$length) {
 668              return $string;
 669          }
 670          
 671          $pos = strrpos($string,".");
 672          if ($pos>=$length-4) {
 673              $string = substr($string,0,$length-4);
 674              $pos = strrpos($string,".");
 675          }
 676          if ($pos>=$length*0.4) {
 677              return substr($string,0,$pos+1)." ...";
 678          }
 679          
 680          $pos = strrpos($string," ");
 681          if ($pos>=$length-4) {
 682              $string = substr($string,0,$length-4);
 683              $pos = strrpos($string," ");
 684          }
 685          if ($pos>=$length*0.4) {
 686              return substr($string,0,$pos)." ...";
 687          }
 688          
 689          return substr($string,0,$length-4)." ...";
 690              
 691      }
 692      
 693      
 694      /**
 695       * Creates a comment indicating the generator of this feed.
 696       * The format of this comment seems to be recognized by
 697       * Syndic8.com.
 698       */
 699  	function _createGeneratorComment() {
 700          return "<!-- generator=\"".FEEDCREATOR_VERSION."\" -->\n";
 701      }
 702      
 703      
 704      /**
 705       * Creates a string containing all additional elements specified in
 706       * $additionalElements.
 707       * @param    elements    array    an associative array containing key => value pairs
 708       * @param indentString    string    a string that will be inserted before every generated line
 709       * @return    string    the XML tags corresponding to $additionalElements
 710       */
 711  	function _createAdditionalElements($elements, $indentString="") {
 712          $ae = "";
 713          if (is_array($elements)) {
 714              foreach($elements AS $key => $value) {
 715                  $ae.= $indentString."<$key>$value</$key>\n";
 716              }
 717          }
 718          return $ae;
 719      }
 720      
 721  	function _createStylesheetReferences() {
 722          $xml = "";
 723          if (!empty($this->cssStyleSheet)) $xml .= "<?xml-stylesheet href=\"".$this->cssStyleSheet."\" type=\"text/css\"?>\n";
 724          if (!empty($this->xslStyleSheet)) $xml .= "<?xml-stylesheet href=\"".$this->xslStyleSheet."\" type=\"text/xsl\"?>\n";
 725          return $xml;
 726      }
 727      
 728      
 729      /**
 730       * Builds the feed's text.
 731       * @abstract
 732       * @return    string    the feed's complete text 
 733       */
 734  	function createFeed() {
 735      }
 736      
 737      /**
 738       * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml.
 739       * For example:
 740       * 
 741       * echo $_SERVER["PHP_SELF"]."\n";
 742       * echo FeedCreator::_generateFilename();
 743       * 
 744       * would produce:
 745       * 
 746       * /rss/latestnews.php
 747       * latestnews.xml
 748       *
 749       * @return string the feed cache filename
 750       * @since 1.4
 751       * @access private
 752       */
 753  	function _generateFilename() {
 754          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
 755          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml";
 756      }
 757      
 758      
 759      /**
 760       * @since 1.4
 761       * @access private
 762       */
 763  	function _redirect($filename) {
 764          // attention, heavily-commented-out-area
 765          
 766          // maybe use this in addition to file time checking
 767          //header("Expires: ".date("r",time()+$this->_timeout));
 768          
 769          /* no caching at all, doesn't seem to work as good:
 770          header("Cache-Control: no-cache");
 771          header("Pragma: no-cache");
 772          */
 773          
 774          // HTTP redirect, some feed readers' simple HTTP implementations don't follow it
 775          //Header("Location: ".$filename);
 776  
 777          //header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename));
 778          header("Content-Type: ".$this->contentType."; charset=".$this->encoding);
 779          header("Content-Disposition: inline; filename=".basename($filename));
 780          readfile($filename, "r");
 781          die();
 782      }
 783      
 784      /**
 785       * Turns on caching and checks if there is a recent version of this feed in the cache.
 786       * If there is, an HTTP redirect header is sent.
 787       * To effectively use caching, you should create the FeedCreator object and call this method
 788       * before anything else, especially before you do the time consuming task to build the feed
 789       * (web fetching, for example).
 790       * @since 1.4
 791       * @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()).
 792       * @param timeout    int        optional    the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
 793       */
 794  	function useCached($filename="", $timeout=3600) {
 795          $this->_timeout = $timeout;
 796          if ($filename=="") {
 797              $filename = $this->_generateFilename();
 798          }
 799          if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) {
 800              $this->_redirect($filename);
 801          }
 802      }
 803      
 804      
 805      /**
 806       * Saves this feed as a file on the local disk. After the file is saved, a redirect
 807       * header may be sent to redirect the user to the newly created file.
 808       * @since 1.4
 809       * 
 810       * @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()).
 811       * @param redirect    boolean    optional    send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file.
 812       */
 813  	function saveFeed($filename="", $displayContents=true) {
 814          if ($filename=="") {
 815              $filename = $this->_generateFilename();
 816          }
 817          // try to set write permissions
 818          if(file_exists($filename) && !is_writable($filename)) {
 819              @chmod($filename, 0666);
 820          }
 821          $feedFile = @fopen($filename, "w+");
 822          if ($feedFile) {
 823              fputs($feedFile,$this->createFeed());
 824              fclose($feedFile);
 825              if ($displayContents) {
 826                  $this->_redirect($filename);
 827              }
 828          } else {
 829              echo "<br /><b>Error creating feed file, please check write permissions.</b><br />";
 830          }
 831      }
 832  
 833      /**
 834       * Outputs this feed directly to the browser - for on-the-fly feed generation
 835       * @since 1.7.2-mod
 836       *
 837       * still missing: proper header output - currently you have to add it manually
 838       */
 839  	function outputFeed() {
 840          echo $this->createFeed();
 841      }
 842  
 843      
 844  }
 845  
 846  
 847  /**
 848   * FeedDate is an internal class that stores a date for a feed or feed item.
 849   * Usually, you won't need to use this.
 850   */
 851  class FeedDate {
 852      var $unix;
 853      
 854      /**
 855       * Creates a new instance of FeedDate representing a given date.
 856       * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps.
 857       * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used.
 858       */
 859  	function FeedDate($dateString="") {
 860          if ($dateString=="") $dateString = date("r");
 861          
 862          if (is_integer($dateString)) {
 863              $this->unix = $dateString;
 864              return;
 865          }
 866          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)) {
 867              $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);
 868              $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]);
 869              if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
 870                  $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
 871              } else {
 872                  if (strlen($matches[7])==1) {
 873                      $oneHour = 3600;
 874                      $ord = ord($matches[7]);
 875                      if ($ord < ord("M")) {
 876                          $tzOffset = (ord("A") - $ord - 1) * $oneHour;
 877                      } elseif ($ord >= ord("M") AND $matches[7]!="Z") {
 878                          $tzOffset = ($ord - ord("M")) * $oneHour;
 879                      } elseif ($matches[7]=="Z") {
 880                          $tzOffset = 0;
 881                      }
 882                  }
 883                  switch ($matches[7]) {
 884                      case "UT":
 885                      case "GMT":    $tzOffset = 0;
 886                  }
 887              }
 888              $this->unix += $tzOffset;
 889              return;
 890          }
 891          if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) {
 892              $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]);
 893              if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
 894                  $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
 895              } else {
 896                  if ($matches[7]=="Z") {
 897                      $tzOffset = 0;
 898                  }
 899              }
 900              $this->unix += $tzOffset;
 901              return;
 902          }
 903          $this->unix = 0;
 904      }
 905  
 906      /**
 907       * Gets the date stored in this FeedDate as an RFC 822 date.
 908       *
 909       * @return a date in RFC 822 format
 910       */
 911  	function rfc822() {
 912          //return gmdate("r",$this->unix);
 913          $date = gmdate("D, d M Y H:i:s", $this->unix);
 914          if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE);
 915          return $date;
 916      }
 917      
 918      /**
 919       * Gets the date stored in this FeedDate as an ISO 8601 date.
 920       *
 921       * @return a date in ISO 8601 (RFC 3339) format
 922       */
 923  	function iso8601() {
 924          $date = gmdate("Y-m-d\TH:i:sO",$this->unix);
 925          $date = substr($date,0,22) . ':' . substr($date,-2);
 926          if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date);
 927          return $date;
 928      }
 929      
 930      /**
 931       * Gets the date stored in this FeedDate as unix time stamp.
 932       *
 933       * @return a date as a unix time stamp
 934       */
 935  	function unix() {
 936          return $this->unix;
 937      }
 938  }
 939  
 940  
 941  /**
 942   * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0.
 943   *
 944   * @see http://www.purl.org/rss/1.0/
 945   * @since 1.3
 946   * @author Kai Blankenhorn <kaib@bitfolge.de>
 947   */
 948  class RSSCreator10 extends FeedCreator {
 949  
 950      /**
 951       * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
 952       * The feed will contain all items previously added in the same order.
 953       * @return    string    the feed's complete text 
 954       */
 955  	function createFeed() {     
 956          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
 957          $feed.= $this->_createGeneratorComment();
 958          if ($this->cssStyleSheet=="") {
 959              $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css";
 960          }
 961          $feed.= $this->_createStylesheetReferences();
 962          $feed.= "<rdf:RDF\n";
 963          $feed.= "    xmlns=\"http://purl.org/rss/1.0/\"\n";
 964          $feed.= "    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; 
 965          $feed.= "    xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n";
 966          $feed.= "    xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
 967          $feed.= "    <channel rdf:about=\"".$this->syndicationURL."\">\n";
 968          $feed.= "        <title>".html_specialchars($this->title)."</title>\n";
 969          $feed.= "        <description>".html_specialchars($this->description)."</description>\n";
 970          $feed.= "        <link>".$this->link."</link>\n";
 971          if ($this->image!=null) {
 972              $feed.= "        <image rdf:resource=\"".$this->image->url."\" />\n";
 973          }
 974          $now = new FeedDate();
 975          $feed.= "       <dc:date>".html_specialchars($now->iso8601())."</dc:date>\n";
 976          $feed.= "        <items>\n";
 977          $feed.= "            <rdf:Seq>\n";
 978          for ($i=0;$i<count($this->items);$i++) {
 979              $feed.= "                <rdf:li rdf:resource=\"".html_specialchars($this->items[$i]->link)."\"/>\n";
 980          }
 981          $feed.= "            </rdf:Seq>\n";
 982          $feed.= "        </items>\n";
 983          $feed.= "    </channel>\n";
 984          if ($this->image!=null) {
 985              $feed.= "    <image rdf:about=\"".$this->image->url."\">\n";
 986              $feed.= "        <title>".$this->image->title."</title>\n";
 987              $feed.= "        <link>".$this->image->link."</link>\n";
 988              $feed.= "        <url>".$this->image->url."</url>\n";
 989              $feed.= "    </image>\n";
 990          }
 991          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
 992          
 993          for ($i=0;$i<count($this->items);$i++) {
 994              $feed.= "    <item rdf:about=\"".html_specialchars($this->items[$i]->link)."\">\n";
 995              //$feed.= "        <dc:type>Posting</dc:type>\n";
 996              $feed.= "        <dc:format>text/html</dc:format>\n";
 997              if ($this->items[$i]->date!=null) {
 998                  $itemDate = new FeedDate($this->items[$i]->date);
 999                  $feed.= "        <dc:date>".html_specialchars($itemDate->iso8601())."</dc:date>\n";
1000              }
1001              if ($this->items[$i]->source!="") {
1002                  $feed.= "        <dc:source>".html_specialchars($this->items[$i]->source)."</dc:source>\n";
1003              }
1004              if ($this->items[$i]->author!="") {
1005                  $feed.= "        <dc:creator>".html_specialchars($this->items[$i]->author)."</dc:creator>\n";
1006              }
1007              $feed.= "        <title>".html_specialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")))."</title>\n";
1008              $feed.= "        <link>".html_specialchars($this->items[$i]->link)."</link>\n";
1009              $feed.= "        <description>".html_specialchars($this->items[$i]->description)."</description>\n";
1010              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1011              $feed.= "    </item>\n";
1012          }
1013          $feed.= "</rdf:RDF>\n";
1014          return $feed;
1015      }
1016  }
1017  
1018  
1019  
1020  /**
1021   * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3.
1022   *
1023   * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html
1024   * @since 1.3
1025   * @author Kai Blankenhorn <kaib@bitfolge.de>
1026   */
1027  class RSSCreator091 extends FeedCreator {
1028  
1029      /**
1030       * Stores this RSS feed's version number.
1031       * @access private
1032       */
1033      var $RSSVersion;
1034  
1035  	function RSSCreator091() {
1036          $this->_setRSSVersion("0.91");
1037          $this->contentType = "application/rss+xml";
1038      }
1039      
1040      /**
1041       * Sets this RSS feed's version number.
1042       * @access private
1043       */
1044  	function _setRSSVersion($version) {
1045          $this->RSSVersion = $version;
1046      }
1047  
1048      /**
1049       * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
1050       * The feed will contain all items previously added in the same order.
1051       * @return    string    the feed's complete text 
1052       */
1053  	function createFeed() {
1054          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1055          $feed.= $this->_createGeneratorComment();
1056          $feed.= $this->_createStylesheetReferences();
1057          $feed.= "<rss version=\"".$this->RSSVersion."\">\n"; 
1058          $feed.= "    <channel>\n";
1059          $feed.= "        <title>".FeedCreator::iTrunc(html_specialchars($this->title),100)."</title>\n";
1060          $this->descriptionTruncSize = 500;
1061          $feed.= "        <description>".$this->getDescription()."</description>\n";
1062          $feed.= "        <link>".$this->link."</link>\n";
1063          $now = new FeedDate();
1064          $feed.= "        <lastBuildDate>".html_specialchars($now->rfc822())."</lastBuildDate>\n";
1065          $feed.= "        <generator>".FEEDCREATOR_VERSION."</generator>\n";
1066  
1067          if ($this->image!=null) {
1068              $feed.= "        <image>\n";
1069              $feed.= "            <url>".$this->image->url."</url>\n"; 
1070              $feed.= "            <title>".FeedCreator::iTrunc(html_specialchars($this->image->title),100)."</title>\n"; 
1071              $feed.= "            <link>".$this->image->link."</link>\n";
1072              if ($this->image->width!="") {
1073                  $feed.= "            <width>".$this->image->width."</width>\n";
1074              }
1075              if ($this->image->height!="") {
1076                  $feed.= "            <height>".$this->image->height."</height>\n";
1077              }
1078              if ($this->image->description!="") {
1079                  $feed.= "            <description>".$this->image->getDescription()."</description>\n";
1080              }
1081              $feed.= "        </image>\n";
1082          }
1083          if ($this->language!="") {
1084              $feed.= "        <language>".$this->language."</language>\n";
1085          }
1086          if ($this->copyright!="") {
1087              $feed.= "        <copyright>".FeedCreator::iTrunc(html_specialchars($this->copyright),100)."</copyright>\n";
1088          }
1089          if ($this->editor!="") {
1090              $feed.= "        <managingEditor>".FeedCreator::iTrunc(html_specialchars($this->editor),100)."</managingEditor>\n";
1091          }
1092          if ($this->webmaster!="") {
1093              $feed.= "        <webMaster>".FeedCreator::iTrunc(html_specialchars($this->webmaster),100)."</webMaster>\n";
1094          }
1095          if ($this->pubDate!="") {
1096              $pubDate = new FeedDate($this->pubDate);
1097              $feed.= "        <pubDate>".html_specialchars($pubDate->rfc822())."</pubDate>\n";
1098          }
1099          if ($this->category!="") {
1100              $feed.= "        <category>".html_specialchars($this->category)."</category>\n";
1101          }
1102          if ($this->docs!="") {
1103              $feed.= "        <docs>".FeedCreator::iTrunc(html_specialchars($this->docs),500)."</docs>\n";
1104          }
1105          if ($this->ttl!="") {
1106              $feed.= "        <ttl>".html_specialchars($this->ttl)."</ttl>\n";
1107          }
1108          if ($this->rating!="") {
1109              $feed.= "        <rating>".FeedCreator::iTrunc(html_specialchars($this->rating),500)."</rating>\n";
1110          }
1111          if ($this->skipHours!="") {
1112              $feed.= "        <skipHours>".html_specialchars($this->skipHours)."</skipHours>\n";
1113          }
1114          if ($this->skipDays!="") {
1115              $feed.= "        <skipDays>".html_specialchars($this->skipDays)."</skipDays>\n";
1116          }
1117          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
1118  
1119          for ($i=0;$i<count($this->items);$i++) {
1120              $feed.= "        <item>\n";
1121              $feed.= "            <title>".FeedCreator::iTrunc(html_specialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
1122              $feed.= "            <link>".html_specialchars($this->items[$i]->link)."</link>\n";
1123              $feed.= "            <description>".$this->items[$i]->getDescription()."</description>\n";
1124              
1125              if ($this->items[$i]->author!="") {
1126                  $feed.= "            <author>".html_specialchars($this->items[$i]->author)."</author>\n";
1127              }
1128              /*
1129              // on hold
1130              if ($this->items[$i]->source!="") {
1131                      $feed.= "            <source>".html_specialchars($this->items[$i]->source)."</source>\n";
1132              }
1133              */
1134              if ($this->items[$i]->category!="") {
1135                  $feed.= "            <category>".html_specialchars($this->items[$i]->category)."</category>\n";
1136              }
1137              if ($this->items[$i]->comments!="") {
1138                  $feed.= "            <comments>".html_specialchars($this->items[$i]->comments)."</comments>\n";
1139              }
1140              if ($this->items[$i]->date!="") {
1141              $itemDate = new FeedDate($this->items[$i]->date);
1142                  $feed.= "            <pubDate>".html_specialchars($itemDate->rfc822())."</pubDate>\n";
1143              }
1144              if ($this->items[$i]->guid!="") {
1145                  $feed.= "            <guid>".html_specialchars($this->items[$i]->guid)."</guid>\n";
1146              }
1147              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1148              
1149              if ($this->RSSVersion == "2.0" && $this->items[$i]->enclosure != NULL)
1150                  {
1151                                  $feed.= "            <enclosure url=\"";
1152                                  $feed.= $this->items[$i]->enclosure->url;
1153                                  $feed.= "\" length=\"";
1154                                  $feed.= $this->items[$i]->enclosure->length;
1155                                  $feed.= "\" type=\"";
1156                                  $feed.= $this->items[$i]->enclosure->type;
1157                                  $feed.= "\"/>\n";
1158                          }
1159                  
1160          
1161          
1162              $feed.= "        </item>\n";
1163          }
1164  
1165          $feed.= "    </channel>\n";
1166          $feed.= "</rss>\n";
1167          return $feed;
1168      }
1169  }
1170  
1171  
1172  
1173  /**
1174   * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0.
1175   *
1176   * @see http://backend.userland.com/rss
1177   * @since 1.3
1178   * @author Kai Blankenhorn <kaib@bitfolge.de>
1179   */
1180  class RSSCreator20 extends RSSCreator091 {
1181  
1182      function RSSCreator20() {
1183          //$this->encoding = "utf-8";
1184          parent::_setRSSVersion("2.0");
1185      }
1186      
1187  }
1188  
1189  
1190  /**
1191   * PIECreator01 is a FeedCreator that implements the emerging PIE specification,
1192   * as in http://intertwingly.net/wiki/pie/Syntax.
1193   *
1194   * @deprecated
1195   * @since 1.3
1196   * @author Scott Reynen <scott@randomchaos.com> and Kai Blankenhorn <kaib@bitfolge.de>
1197   */
1198  class PIECreator01 extends FeedCreator {
1199      
1200  	function PIECreator01() {
1201          $this->encoding = FEED_ENCODING; //"utf-8"
1202      }
1203      
1204  	function createFeed() {
1205          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1206          $feed.= $this->_createStylesheetReferences();
1207          $feed.= "<feed version=\"0.1\" xmlns=\"http://example.com/newformat#\">\n"; 
1208          $feed.= "    <title>".FeedCreator::iTrunc(html_specialchars($this->title),100)."</title>\n";
1209          $this->truncSize = 500;
1210          $feed.= "    <subtitle>".$this->getDescription()."</subtitle>\n";
1211          $feed.= "    <link>".$this->link."</link>\n";
1212          for ($i=0;$i<count($this->items);$i++) {
1213              $feed.= "    <entry>\n";
1214              $feed.= "        <title>".FeedCreator::iTrunc(html_specialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
1215              $feed.= "        <link>".html_specialchars($this->items[$i]->link)."</link>\n";
1216              $itemDate = new FeedDate($this->items[$i]->date);
1217              $feed.= "        <created>".html_specialchars($itemDate->iso8601())."</created>\n";
1218              $feed.= "        <issued>".html_specialchars($itemDate->iso8601())."</issued>\n";
1219              $feed.= "        <modified>".html_specialchars($itemDate->iso8601())."</modified>\n";
1220              $feed.= "        <id>".html_specialchars($this->items[$i]->guid)."</id>\n";
1221              if ($this->items[$i]->author!="") {
1222                  $feed.= "        <author>\n";
1223                  $feed.= "            <name>".html_specialchars($this->items[$i]->author)."</name>\n";
1224                  if ($this->items[$i]->authorEmail!="") {
1225                      $feed.= "            <email>".$this->items[$i]->authorEmail."</email>\n";
1226                  }
1227                  $feed.="        </author>\n";
1228              }
1229              $feed.= "        <content type=\"text/html\" xml:lang=\"en-us\">\n";
1230              $feed.= "            <div xmlns=\"http://www.w3.org/1999/xhtml\">".$this->items[$i]->getDescription()."</div>\n";
1231              $feed.= "        </content>\n";
1232              $feed.= "    </entry>\n";
1233          }
1234          $feed.= "</feed>\n";
1235          return $feed;
1236      }
1237  }
1238  
1239  /**
1240   * AtomCreator10 is a FeedCreator that implements the atom specification,
1241   * as in http://www.atomenabled.org/developers/syndication/atom-format-spec.php
1242   * Please note that just by using AtomCreator10 you won't automatically
1243   * produce valid atom files. For example, you have to specify either an editor
1244   * for the feed or an author for every single feed item.
1245   *
1246   * Some elements have not been implemented yet. These are (incomplete list):
1247   * author URL, item author's email and URL, item contents, alternate links, 
1248   * other link content types than text/html. Some of them may be created with
1249   * AtomCreator10::additionalElements.
1250   *
1251   * @see FeedCreator#additionalElements
1252   * @since 1.7.2-mod (modified)
1253   * @author Mohammad Hafiz Ismail (mypapit@gmail.com)
1254   */
1255   class AtomCreator10 extends FeedCreator {
1256   
1257  	function AtomCreator10() {
1258          $this->contentType = "application/atom+xml";
1259          //$this->encoding = "utf-8";
1260      }
1261  
1262  	function createFeed() {
1263          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1264          $feed.= $this->_createGeneratorComment();
1265          $feed.= $this->_createStylesheetReferences();
1266          $feed.= "<feed xmlns=\"http://www.w3.org/2005/Atom\"";
1267          if ($this->language!="") {
1268              $feed.= " xml:lang=\"".$this->language."\"";
1269          }
1270          $feed.= ">\n"; 
1271          $feed.= "    <title>".html_specialchars($this->title)."</title>\n";
1272          $feed.= "    <subtitle>".html_specialchars($this->description)."</subtitle>\n";
1273          $feed.= "    <link rel=\"alternate\" type=\"text/html\" href=\"".html_specialchars($this->link)."\"/>\n";
1274          $feed.= "    <id>".html_specialchars($this->link)."</id>\n";
1275          $now = new FeedDate();
1276          $feed.= "    <updated>".html_specialchars($now->iso8601())."</updated>\n";
1277          if ($this->editor!="") {
1278              $feed.= "    <author>\n";
1279              $feed.= "        <name>".$this->editor."</name>\n";
1280              if ($this->editorEmail!="") {
1281                  $feed.= "        <email>".$this->editorEmail."</email>\n";
1282              }
1283              $feed.= "    </author>\n";
1284          }
1285          $feed.= "    <generator>".FEEDCREATOR_VERSION."</generator>\n";
1286          $feed.= "<link rel=\"self\" type=\"application/atom+xml\" href=\"". $this->syndicationURL . "\" />\n";
1287          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
1288          for ($i=0;$i<count($this->items);$i++) {
1289              $feed.= "    <entry>\n";
1290              $feed.= "        <title>".html_specialchars(strip_tags($this->items[$i]->title))."</title>\n";
1291              $feed.= "        <link rel=\"alternate\" type=\"text/html\" href=\"".html_specialchars($this->items[$i]->link)."\"/>\n";
1292              if ($this->items[$i]->date=="") {
1293                  $this->items[$i]->date = time();
1294              }
1295              $itemDate = new FeedDate($this->items[$i]->date);
1296              $feed.= "        <published>".html_specialchars($itemDate->iso8601())."</published>\n";
1297              if(isset($this->items[$i]->updateDate)) {
1298                  $itemUpdateDate = new FeedDate($this->items[$i]->updateDate);
1299              } else {
1300                  $itemUpdateDate = $itemDate;
1301              }
1302              $feed.= "        <updated>".html_specialchars($itemUpdateDate->iso8601())."</updated>\n";
1303              $feed.= "        <id>".html_specialchars($this->items[$i]->link)."</id>\n";
1304              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1305              if ($this->items[$i]->author!="") {
1306                  $feed.= "        <author>\n";
1307                  $feed.= "            <name>".html_specialchars($this->items[$i]->author)."</name>\n";
1308                  $feed.= "        </author>\n";
1309              }
1310              //if ($this->items[$i]->description!="") {
1311                  $feed.= "        <summary>".html_specialchars($this->items[$i]->description)."</summary>\n";
1312              //}
1313              if ($this->items[$i]->enclosure != NULL) {
1314              $feed.="        <link rel=\"enclosure\" href=\"". $this->items[$i]->enclosure->url ."\" type=\"". $this->items[$i]->enclosure->type."\"  length=\"". $this->items[$i]->enclosure->length . "\" />\n";
1315              }
1316              $feed.= "    </entry>\n";
1317          }
1318          $feed.= "</feed>\n";
1319          return $feed;
1320      }
1321  
1322      
1323  }
1324   
1325   
1326  /**
1327   * AtomCreator03 is a FeedCreator that implements the atom specification,
1328   * as in http://www.intertwingly.net/wiki/pie/FrontPage.
1329   * Please note that just by using AtomCreator03 you won't automatically
1330   * produce valid atom files. For example, you have to specify either an editor
1331   * for the feed or an author for every single feed item.
1332   *
1333   * Some elements have not been implemented yet. These are (incomplete list):
1334   * author URL, item author's email and URL, item contents, alternate links, 
1335   * other link content types than text/html. Some of them may be created with
1336   * AtomCreator03::additionalElements.
1337   *
1338   * @see FeedCreator#additionalElements
1339   * @since 1.6
1340   * @author Kai Blankenhorn <kaib@bitfolge.de>, Scott Reynen <scott@randomchaos.com>
1341   */
1342  class AtomCreator03 extends FeedCreator {
1343  
1344  	function AtomCreator03() {
1345          $this->contentType = "application/atom+xml";
1346          //$this->encoding = "utf-8";
1347      }
1348      
1349  	function createFeed() {
1350          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1351          $feed.= $this->_createGeneratorComment();
1352          $feed.= $this->_createStylesheetReferences();
1353          $feed.= "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\"";
1354          if ($this->language!="") {
1355              $feed.= " xml:lang=\"".$this->language."\"";
1356          }
1357          $feed.= ">\n"; 
1358          $feed.= "    <title>".html_specialchars($this->title)."</title>\n";
1359          $feed.= "    <tagline>".html_specialchars($this->description)."</tagline>\n";
1360          $feed.= "    <link rel=\"alternate\" type=\"text/html\" href=\"".html_specialchars($this->link)."\"/>\n";
1361          $feed.= "    <id>".html_specialchars($this->link)."</id>\n";
1362          $now = new FeedDate();
1363          $feed.= "    <modified>".html_specialchars($now->iso8601())."</modified>\n";
1364          if ($this->editor!="") {
1365              $feed.= "    <author>\n";
1366              $feed.= "        <name>".$this->editor."</name>\n";
1367              if ($this->editorEmail!="") {
1368                  $feed.= "        <email>".$this->editorEmail."</email>\n";
1369              }
1370              $feed.= "    </author>\n";
1371          }
1372          $feed.= "    <generator>".FEEDCREATOR_VERSION."</generator>\n";
1373          $feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
1374          for ($i=0;$i<count($this->items);$i++) {
1375              $feed.= "    <entry>\n";
1376              $feed.= "        <title>".html_specialchars(strip_tags($this->items[$i]->title))."</title>\n";
1377              $feed.= "        <link rel=\"alternate\" type=\"text/html\" href=\"".html_specialchars($this->items[$i]->link)."\"/>\n";
1378              if ($this->items[$i]->date=="") {
1379                  $this->items[$i]->date = time();
1380              }
1381              $itemDate = new FeedDate($this->items[$i]->date);
1382              $feed.= "        <created>".html_specialchars($itemDate->iso8601())."</created>\n";
1383              $feed.= "        <issued>".html_specialchars($itemDate->iso8601())."</issued>\n";
1384              $feed.= "        <modified>".html_specialchars($itemDate->iso8601())."</modified>\n";
1385              $feed.= "        <id>".html_specialchars($this->items[$i]->link)."</id>\n";
1386              $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
1387              if ($this->items[$i]->author!="") {
1388                  $feed.= "        <author>\n";
1389                  $feed.= "            <name>".html_specialchars($this->items[$i]->author)."</name>\n";
1390                  $feed.= "        </author>\n";
1391              }
1392              if ($this->items[$i]->description!="") {
1393                  $feed.= "        <summary>".html_specialchars($this->items[$i]->description)."</summary>\n";
1394              }
1395              $feed.= "    </entry>\n";
1396          }
1397          $feed.= "</feed>\n";
1398          return $feed;
1399      }
1400  }
1401  
1402  
1403  /**
1404   * MBOXCreator is a FeedCreator that implements the mbox format
1405   * as described in http://www.qmail.org/man/man5/mbox.html
1406   *
1407   * @since 1.3
1408   * @author Kai Blankenhorn <kaib@bitfolge.de>
1409   */
1410  class MBOXCreator extends FeedCreator {
1411  
1412  	function MBOXCreator() {
1413          $this->contentType = "text/plain";
1414          $this->encoding = FEED_ENCODING; //"ISO-8859-15"
1415      }
1416      
1417  	function qp_enc($input = "", $line_max = 76) { 
1418          $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); 
1419          $lines = preg_split("/(?:\r\n|\r|\n)/", $input); 
1420          $eol = "\r\n"; 
1421          $escape = "="; 
1422          $output = ""; 
1423          while( list(, $line) = each($lines) ) { 
1424              //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary 
1425              $linlen = strlen($line); 
1426              $newline = ""; 
1427              for($i = 0; $i < $linlen; $i++) { 
1428                  $c = substr($line, $i, 1); 
1429                  $dec = ord($c); 
1430                  if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only 
1431                      $c = "=20"; 
1432                  } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required 
1433                      $h2 = floor($dec/16); $h1 = floor($dec%16); 
1434                      $c = $escape.$hex["$h2"].$hex["$h1"]; 
1435                  } 
1436                  if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted 
1437                      $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay 
1438                      $newline = ""; 
1439                  } 
1440                  $newline .= $c; 
1441              } // end of for 
1442              $output .= $newline.$eol; 
1443          } 
1444          return trim($output); 
1445      }
1446      
1447  
1448      /**
1449       * Builds the MBOX contents.
1450       * @return    string    the feed's complete text 
1451       */
1452  	function createFeed() {
1453          for ($i=0;$i<count($this->items);$i++) {
1454              if ($this->items[$i]->author!="") {
1455                  $from = $this->items[$i]->author;
1456              } else {
1457                  $from = $this->title;
1458              }
1459              $itemDate = new FeedDate($this->items[$i]->date);
1460              $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n";
1461              $feed.= "Content-Type: text/plain;\n";
1462              $feed.= "    charset=\"".$this->encoding."\"\n";
1463              $feed.= "Content-Transfer-Encoding: quoted-printable\n";
1464              $feed.= "Content-Type: text/plain\n";
1465              $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n";
1466              $feed.= "Date: ".$itemDate->rfc822()."\n";
1467              $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n";
1468              $feed.= "\n";
1469              $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description));
1470              $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body);
1471              $feed.= "\n";
1472              $feed.= "\n";
1473          }
1474          return $feed;
1475      }
1476      
1477      /**
1478       * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types.
1479       * @return string the feed cache filename
1480       * @since 1.4
1481       * @access private
1482       */
1483  	function _generateFilename() {
1484          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1485          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox";
1486      }
1487  }
1488  
1489  
1490  /**
1491   * OPMLCreator is a FeedCreator that implements OPML 1.0.
1492   * 
1493   * @see http://opml.scripting.com/spec
1494   * @author Dirk Clemens, Kai Blankenhorn
1495   * @since 1.5
1496   */
1497  class OPMLCreator extends FeedCreator {
1498  
1499  	function OPMLCreator() {
1500          $this->encoding = FEED_ENCODING; //"utf-8"
1501      }
1502      
1503  	function createFeed() {     
1504          $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1505          $feed.= $this->_createGeneratorComment();
1506          $feed.= $this->_createStylesheetReferences();
1507          $feed.= "<opml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
1508          $feed.= "    <head>\n";
1509          $feed.= "        <title>".html_specialchars($this->title)."</title>\n";
1510          if ($this->pubDate!="") {
1511              $date = new FeedDate($this->pubDate);
1512              $feed.= "         <dateCreated>".$date->rfc822()."</dateCreated>\n";
1513          }
1514          if ($this->lastBuildDate!="") {
1515              $date = new FeedDate($this->lastBuildDate);
1516              $feed.= "         <dateModified>".$date->rfc822()."</dateModified>\n";
1517          }
1518          if ($this->editor!="") {
1519              $feed.= "         <ownerName>".$this->editor."</ownerName>\n";
1520          }
1521          if ($this->editorEmail!="") {
1522              $feed.= "         <ownerEmail>".$this->editorEmail."</ownerEmail>\n";
1523          }
1524          $feed.= "    </head>\n";
1525          $feed.= "    <body>\n";
1526          for ($i=0;$i<count($this->items);$i++) {
1527              $feed.= "    <outline type=\"rss\" ";
1528              $title = html_specialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")));
1529              $feed.= " title=\"".$title."\"";
1530              $feed.= " text=\"".$title."\"";
1531              //$feed.= " description=\"".html_specialchars($this->items[$i]->description)."\"";
1532              $feed.= " url=\"".html_specialchars($this->items[$i]->link)."\"";
1533              $feed.= "/>\n";
1534          }
1535          $feed.= "    </body>\n";
1536          $feed.= "</opml>\n";
1537          return $feed;
1538      }
1539  }
1540  
1541  
1542  
1543  /**
1544   * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific 
1545   * location, overriding the createFeed method of the parent FeedCreator.
1546   * The HTML produced can be included over http by scripting languages, or serve
1547   * as the source for an IFrame.
1548   * All output by this class is embedded in <div></div> tags to enable formatting
1549   * using CSS. 
1550   *
1551   * @author Pascal Van Hecke
1552   * @since 1.7
1553   */
1554  class HTMLCreator extends FeedCreator {
1555  
1556      var $contentType = "text/html";
1557      
1558      /**
1559       * Contains HTML to be output at the start of the feed's html representation.
1560       */
1561      var $header;
1562      
1563      /**
1564       * Contains HTML to be output at the end of the feed's html representation.
1565       */
1566      var $footer ;
1567      
1568      /**
1569       * Contains HTML to be output between entries. A separator is only used in 
1570       * case of multiple entries.
1571       */
1572      var $separator;
1573      
1574      /**
1575       * Used to prefix the stylenames to make sure they are unique 
1576       * and do not clash with stylenames on the users' page.
1577       */
1578      var $stylePrefix;
1579      
1580      /**
1581       * Determines whether the links open in a new window or not.
1582       */
1583      var $openInNewWindow = true;
1584      
1585      var $imageAlign ="right";
1586      
1587      /**
1588       * In case of very simple output you may want to get rid of the style tags,
1589       * hence this variable.  There's no equivalent on item level, but of course you can 
1590       * add strings to it while iterating over the items ($this->stylelessOutput .= ...)
1591       * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored
1592       * in the function createFeed().
1593       */
1594      var $stylelessOutput ="";
1595  
1596      /**
1597       * Writes the HTML.
1598       * @return    string    the scripts's complete text 
1599       */
1600  	function createFeed() {
1601          // if there is styleless output, use the content of this variable and ignore the rest
1602          if ($this->stylelessOutput!="") {
1603              return $this->stylelessOutput;
1604          }
1605          
1606          //if no stylePrefix is set, generate it yourself depending on the script name
1607          if ($this->stylePrefix=="") {
1608              $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_";
1609          }
1610  
1611          //set an openInNewWindow_token_to be inserted or not
1612          if ($this->openInNewWindow) {
1613              $targetInsert = " target='_blank'";
1614          }
1615          
1616          // use this array to put the lines in and implode later with "document.write" javascript
1617          $feedArray = array();
1618          if ($this->image!=null) {
1619              $imageStr = "<a href='".$this->image->link."'".$targetInsert.">".
1620                              "<img src='".$this->image->url."' border='0' alt='".
1621                              FeedCreator::iTrunc(html_specialchars($this->image->title),100).
1622                              "' align='".$this->imageAlign."' ";
1623              if ($this->image->width) {
1624                  $imageStr .=" width='".$this->image->width. "' ";
1625              }
1626              if ($this->image->height) {
1627                  $imageStr .=" height='".$this->image->height."' ";
1628              }
1629              $imageStr .="/></a>";
1630              $feedArray[] = $imageStr;
1631          }
1632          
1633          if ($this->title) {
1634              $feedArray[] = "<div class='".$this->stylePrefix."title'><a href='".$this->link."' ".$targetInsert." class='".$this->stylePrefix."title'>".
1635                  FeedCreator::iTrunc(html_specialchars($this->title),100)."</a></div>";
1636          }
1637          if ($this->getDescription()) {
1638              $feedArray[] = "<div class='".$this->stylePrefix."description'>".
1639                  str_replace("]]>", "", str_replace("<![CDATA[", "", $this->getDescription())).
1640                  "</div>";
1641          }
1642          
1643          if ($this->header) {
1644              $feedArray[] = "<div class='".$this->stylePrefix."header'>".$this->header."</div>";
1645          }
1646          
1647          for ($i=0;$i<count($this->items);$i++) {
1648              if ($this->separator and $i > 0) {
1649                  $feedArray[] = "<div class='".$this->stylePrefix."separator'>".$this->separator."</div>";
1650              }
1651              
1652              if ($this->items[$i]->title) {
1653                  if ($this->items[$i]->link) {
1654                      $feedArray[] = 
1655                          "<div class='".$this->stylePrefix."item_title'><a href='".$this->items[$i]->link."' class='".$this->stylePrefix.
1656                          "item_title'".$targetInsert.">".FeedCreator::iTrunc(html_specialchars(strip_tags($this->items[$i]->title)),100).
1657                          "</a></div>";
1658                  } else {
1659                      $feedArray[] = 
1660                          "<div class='".$this->stylePrefix."item_title'>".
1661                          FeedCreator::iTrunc(html_specialchars(strip_tags($this->items[$i]->title)),100).
1662                          "</div>";
1663                  }
1664              }
1665              if ($this->items[$i]->getDescription()) {
1666                  $feedArray[] = 
1667                  "<div class='".$this->stylePrefix."item_description'>".
1668                      str_replace("]]>", "", str_replace("<![CDATA[", "", $this->items[$i]->getDescription())).
1669                      "</div>";
1670              }
1671          }
1672          if ($this->footer) {
1673              $feedArray[] = "<div class='".$this->stylePrefix."footer'>".$this->footer."</div>";
1674          }
1675          
1676          $feed= "".join($feedArray, "\r\n");
1677          return $feed;
1678      }
1679      
1680      /**
1681       * Overrrides parent to produce .html extensions
1682       *
1683       * @return string the feed cache filename
1684       * @since 1.4
1685       * @access private
1686       */
1687  	function _generateFilename() {
1688          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1689          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html";
1690      }
1691  }    
1692  
1693  
1694  /**
1695   * JSCreator is a class that writes a js file to a specific 
1696   * location, overriding the createFeed method of the parent HTMLCreator.
1697   *
1698   * @author Pascal Van Hecke
1699   */
1700  class JSCreator extends HTMLCreator {
1701      var $contentType = "text/javascript";
1702      
1703      /**
1704       * writes the javascript
1705       * @return    string    the scripts's complete text 
1706       */
1707  	function createFeed() 
1708      {
1709          $feed = parent::createFeed();
1710          $feedArray = explode("\n",$feed);
1711          
1712          $jsFeed = "";
1713          foreach ($feedArray as $value) {
1714              $jsFeed .= "document.write('".trim(addslashes($value))."');\n";
1715          }
1716          return $jsFeed;
1717      }
1718      
1719      /**
1720       * Overrrides parent to produce .js extensions
1721       *
1722       * @return string the feed cache filename
1723       * @since 1.4
1724       * @access private
1725       */
1726  	function _generateFilename() {
1727          $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1728          return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js";
1729      }
1730      
1731  }    
1732  
1733  
1734  
1735  /*** TEST SCRIPT *********************************************************
1736  
1737  //include("feedcreator.class.php"); 
1738  
1739  $rss = new UniversalFeedCreator(); 
1740  $rss->useCached(); 
1741  $rss->title = "PHP news"; 
1742  $rss->description = "daily news from the PHP scripting world"; 
1743  
1744  //optional
1745  //$rss->descriptionTruncSize = 500;
1746  //$rss->descriptionHtmlSyndicated = true;
1747  //$rss->xslStyleSheet = "http://feedster.com/rss20.xsl";
1748  
1749  $rss->link = "http://www.dailyphp.net/news"; 
1750  $rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF; 
1751  
1752  $image = new FeedImage(); 
1753  $image->title = "dailyphp.net logo"; 
1754  $image->url = "http://www.dailyphp.net/images/logo.gif"; 
1755  $image->link = "http://www.dailyphp.net"; 
1756  $image->description = "Feed provided by dailyphp.net. Click to visit."; 
1757  
1758  //optional
1759  $image->descriptionTruncSize = 500;
1760  $image->descriptionHtmlSyndicated = true;
1761  
1762  $rss->image = $image; 
1763  
1764  // get your news items from somewhere, e.g. your database: 
1765  //mysql_select_db($dbHost, $dbUser, $dbPass); 
1766  //$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); 
1767  //while ($data = mysql_fetch_object($res)) { 
1768      $item = new FeedItem(); 
1769      $item->title = "This is an the test title of an item"; 
1770      $item->link = "http://localhost/item/"; 
1771      $item->description = "<b>description in </b><br/>HTML"; 
1772      
1773      //optional
1774      //item->descriptionTruncSize = 500;
1775      $item->descriptionHtmlSyndicated = true;
1776      
1777      $item->date = time(); 
1778      $item->source = "http://www.dailyphp.net"; 
1779      $item->author = "John Doe"; 
1780       
1781      $rss->addItem($item); 
1782  //} 
1783  
1784  // valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS
1785  echo $rss->saveFeed("RSS0.91", "feed.xml"); 
1786  
1787  
1788  
1789  ***************************************************************************/
1790  
1791  ?>


Generated: Wed Dec 30 05:55:15 2009 Cross-referenced by PHPXref 0.7