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