[ Index ] |
PHP Cross Reference of phpwcms V1.5.0 _r431 (28.01.12) |
[Summary view] [Print] [Text view]
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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Jan 29 16:31:14 2012 | Cross-referenced by PHPXref 0.7.1 |