jablonka.czprosek.czf

websvn

Subversion Repositories:
[/] [lib/] [feedcreator.class.php] - Blame information for rev 3

 

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

Powered by WebSVN 2.2.1