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