test3
[mirrors/Kyberia-bloodline.git] / trash / feedcreator.class.php
1 <?php
2 /***************************************************************************
3
4 FeedCreator class v1.7.2
5 originally (c) Kai Blankenhorn
6 www.bitfolge.de
7 kaib@bitfolge.de
8 v1.3 work by Scott Reynen (scott@randomchaos.com) and Kai Blankenhorn
9 v1.5 OPML support by Dirk Clemens
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2.1 of the License, or (at your option) any later version.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
25 ****************************************************************************
26
27
28 Changelog:
29
30 v1.7.2 10-11-04
31 license changed to LGPL
32
33 v1.7.1
34 fixed a syntax bug
35 fixed left over debug code
36
37 v1.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
49 v1.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
57 v1.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
64 v1.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
68 v1.5 01-06-04
69 added support for OPML 1.0
70 added more documentation
71
72 v1.4 11-11-03
73 optional feed saving and caching
74 improved documentation
75 minor improvements
76
77 v1.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
82 v1.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
89 v1.1 06-29-03
90 added images to feeds
91 now includes most RSS 0.91 attributes
92 added RSS 2.0 feeds
93
94 v1.0 06-24-03
95 initial release
96
97
98
99 ***************************************************************************/
100
101 /*** GENERAL USAGE *********************************************************
102
103 include("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:
130 mysql_select_db($dbHost, $dbUser, $dbPass);
131 $res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");
132 while ($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
151 echo $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
159 define("TIME_ZONE","+01:00");
160
161
162
163
164 /**
165 * Version string.
166 **/
167 define("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 */
177 class 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 */
224 class 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 */
242 class 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 */
275 class 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 */
333 class 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 */
459 class 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 = "cp1250";
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 function showFeed($format)
697 {
698 echo $this->createFeed($format);
699 }
700
701 }
702
703
704 /**
705 * FeedDate is an internal class that stores a date for a feed or feed item.
706 * Usually, you won't need to use this.
707 */
708 class FeedDate {
709 var $unix;
710
711 /**
712 * Creates a new instance of FeedDate representing a given date.
713 * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps.
714 * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used.
715 */
716 function FeedDate($dateString="") {
717 if ($dateString=="") $dateString = date("r");
718
719 if (is_integer($dateString)) {
720 $this->unix = $dateString;
721 return;
722 }
723 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)) {
724 $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);
725 $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]);
726 if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
727 $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
728 } else {
729 if (strlen($matches[7])==1) {
730 $oneHour = 3600;
731 $ord = ord($matches[7]);
732 if ($ord < ord("M")) {
733 $tzOffset = (ord("A") - $ord - 1) * $oneHour;
734 } elseif ($ord >= ord("M") AND $matches[7]!="Z") {
735 $tzOffset = ($ord - ord("M")) * $oneHour;
736 } elseif ($matches[7]=="Z") {
737 $tzOffset = 0;
738 }
739 }
740 switch ($matches[7]) {
741 case "UT":
742 case "GMT": $tzOffset = 0;
743 }
744 }
745 $this->unix += $tzOffset;
746 return;
747 }
748 if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) {
749 $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]);
750 if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
751 $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
752 } else {
753 if ($matches[7]=="Z") {
754 $tzOffset = 0;
755 }
756 }
757 $this->unix += $tzOffset;
758 return;
759 }
760 $this->unix = 0;
761 }
762
763 /**
764 * Gets the date stored in this FeedDate as an RFC 822 date.
765 *
766 * @return a date in RFC 822 format
767 */
768 function rfc822() {
769 //return gmdate("r",$this->unix);
770 $date = gmdate("D, d M Y H:i:s", $this->unix);
771 if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE);
772 return $date;
773 }
774
775 /**
776 * Gets the date stored in this FeedDate as an ISO 8601 date.
777 *
778 * @return a date in ISO 8601 format
779 */
780 function iso8601() {
781 $date = gmdate("Y-m-d\TH:i:sO",$this->unix);
782 $date = substr($date,0,22) . ':' . substr($date,-2);
783 if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date);
784 return $date;
785 }
786
787 /**
788 * Gets the date stored in this FeedDate as unix time stamp.
789 *
790 * @return a date as a unix time stamp
791 */
792 function unix() {
793 return $this->unix;
794 }
795 }
796
797
798 /**
799 * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0.
800 *
801 * @see http://www.purl.org/rss/1.0/
802 * @since 1.3
803 * @author Kai Blankenhorn <kaib@bitfolge.de>
804 */
805 class RSSCreator10 extends FeedCreator {
806
807 /**
808 * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
809 * The feed will contain all items previously added in the same order.
810 * @return string the feed's complete text
811 */
812 function createFeed() {
813 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
814 $feed.= $this->_createGeneratorComment();
815 if ($this->cssStyleSheet=="") {
816 $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css";
817 }
818 $feed.= $this->_createStylesheetReferences();
819 $feed.= "<rdf:RDF\n";
820 $feed.= " xmlns=\"http://purl.org/rss/1.0/\"\n";
821 $feed.= " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n";
822 $feed.= " xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n";
823 $feed.= " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
824 $feed.= " <channel rdf:about=\"".$this->syndicationURL."\">\n";
825 $feed.= " <title>".htmlspecialchars($this->title)."</title>\n";
826 $feed.= " <description>".htmlspecialchars($this->description)."</description>\n";
827 $feed.= " <link>".$this->link."</link>\n";
828 if ($this->image!=null) {
829 $feed.= " <image rdf:resource=\"".$this->image->url."\" />\n";
830 }
831 $now = new FeedDate();
832 $feed.= " <dc:date>".htmlspecialchars($now->iso8601())."</dc:date>\n";
833 $feed.= " <items>\n";
834 $feed.= " <rdf:Seq>\n";
835 for ($i=0;$i<count($this->items);$i++) {
836 $feed.= " <rdf:li rdf:resource=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
837 }
838 $feed.= " </rdf:Seq>\n";
839 $feed.= " </items>\n";
840 $feed.= " </channel>\n";
841 if ($this->image!=null) {
842 $feed.= " <image rdf:about=\"".$this->image->url."\">\n";
843 $feed.= " <title>".$this->image->title."</title>\n";
844 $feed.= " <link>".$this->image->link."</link>\n";
845 $feed.= " <url>".$this->image->url."</url>\n";
846 $feed.= " </image>\n";
847 }
848 $feed.= $this->_createAdditionalElements($this->additionalElements, " ");
849
850 for ($i=0;$i<count($this->items);$i++) {
851 $feed.= " <item rdf:about=\"".htmlspecialchars($this->items[$i]->link)."\">\n";
852 //$feed.= " <dc:type>Posting</dc:type>\n";
853 $feed.= " <dc:format>text/html</dc:format>\n";
854 if ($this->items[$i]->date!=null) {
855 $itemDate = new FeedDate($this->items[$i]->date);
856 $feed.= " <dc:date>".htmlspecialchars($itemDate->iso8601())."</dc:date>\n";
857 }
858 if ($this->items[$i]->source!="") {
859 $feed.= " <dc:source>".htmlspecialchars($this->items[$i]->source)."</dc:source>\n";
860 }
861 if ($this->items[$i]->author!="") {
862 $feed.= " <dc:creator>".htmlspecialchars($this->items[$i]->author)."</dc:creator>\n";
863 }
864 $feed.= " <title>".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")))."</title>\n";
865 $feed.= " <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
866 $feed.= " <description>".htmlspecialchars($this->items[$i]->description)."</description>\n";
867 $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " ");
868 $feed.= " </item>\n";
869 }
870 $feed.= "</rdf:RDF>\n";
871 return $feed;
872 }
873 }
874
875
876
877 /**
878 * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3.
879 *
880 * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html
881 * @since 1.3
882 * @author Kai Blankenhorn <kaib@bitfolge.de>
883 */
884 class RSSCreator091 extends FeedCreator {
885
886 /**
887 * Stores this RSS feed's version number.
888 * @access private
889 */
890 var $RSSVersion;
891
892 function RSSCreator091() {
893 $this->_setRSSVersion("0.91");
894 $this->contentType = "application/rss+xml";
895 }
896
897 /**
898 * Sets this RSS feed's version number.
899 * @access private
900 */
901 function _setRSSVersion($version) {
902 $this->RSSVersion = $version;
903 }
904
905 /**
906 * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
907 * The feed will contain all items previously added in the same order.
908 * @return string the feed's complete text
909 */
910 function createFeed() {
911 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
912 $feed.= $this->_createGeneratorComment();
913 $feed.= $this->_createStylesheetReferences();
914 $feed.= "<rss version=\"".$this->RSSVersion."\">\n";
915 $feed.= " <channel>\n";
916 $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
917 $this->descriptionTruncSize = 500;
918 $feed.= " <description>".$this->getDescription()."</description>\n";
919 $feed.= " <link>".$this->link."</link>\n";
920 $now = new FeedDate();
921 $feed.= " <lastBuildDate>".htmlspecialchars($now->rfc822())."</lastBuildDate>\n";
922 $feed.= " <generator>".FEEDCREATOR_VERSION."</generator>\n";
923
924 if ($this->image!=null) {
925 $feed.= " <image>\n";
926 $feed.= " <url>".$this->image->url."</url>\n";
927 $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."</title>\n";
928 $feed.= " <link>".$this->image->link."</link>\n";
929 if ($this->image->width!="") {
930 $feed.= " <width>".$this->image->width."</width>\n";
931 }
932 if ($this->image->height!="") {
933 $feed.= " <height>".$this->image->height."</height>\n";
934 }
935 if ($this->image->description!="") {
936 $feed.= " <description>".$this->image->getDescription()."</description>\n";
937 }
938 $feed.= " </image>\n";
939 }
940 if ($this->language!="") {
941 $feed.= " <language>".$this->language."</language>\n";
942 }
943 if ($this->copyright!="") {
944 $feed.= " <copyright>".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."</copyright>\n";
945 }
946 if ($this->editor!="") {
947 $feed.= " <managingEditor>".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."</managingEditor>\n";
948 }
949 if ($this->webmaster!="") {
950 $feed.= " <webMaster>".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."</webMaster>\n";
951 }
952 if ($this->pubDate!="") {
953 $pubDate = new FeedDate($this->pubDate);
954 $feed.= " <pubDate>".htmlspecialchars($pubDate->rfc822())."</pubDate>\n";
955 }
956 if ($this->category!="") {
957 $feed.= " <category>".htmlspecialchars($this->category)."</category>\n";
958 }
959 if ($this->docs!="") {
960 $feed.= " <docs>".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."</docs>\n";
961 }
962 if ($this->ttl!="") {
963 $feed.= " <ttl>".htmlspecialchars($this->ttl)."</ttl>\n";
964 }
965 if ($this->rating!="") {
966 $feed.= " <rating>".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."</rating>\n";
967 }
968 if ($this->skipHours!="") {
969 $feed.= " <skipHours>".htmlspecialchars($this->skipHours)."</skipHours>\n";
970 }
971 if ($this->skipDays!="") {
972 $feed.= " <skipDays>".htmlspecialchars($this->skipDays)."</skipDays>\n";
973 }
974 $feed.= $this->_createAdditionalElements($this->additionalElements, " ");
975
976 for ($i=0;$i<count($this->items);$i++) {
977 $feed.= " <item>\n";
978 $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
979 $feed.= " <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
980 $feed.= " <description>".$this->items[$i]->getDescription()."</description>\n";
981
982 if ($this->items[$i]->author!="") {
983 $feed.= " <author>".htmlspecialchars($this->items[$i]->author)."</author>\n";
984 }
985 /*
986 // on hold
987 if ($this->items[$i]->source!="") {
988 $feed.= " <source>".htmlspecialchars($this->items[$i]->source)."</source>\n";
989 }
990 */
991 if ($this->items[$i]->category!="") {
992 $feed.= " <category>".htmlspecialchars($this->items[$i]->category)."</category>\n";
993 }
994 if ($this->items[$i]->comments!="") {
995 $feed.= " <comments>".htmlspecialchars($this->items[$i]->comments)."</comments>\n";
996 }
997 if ($this->items[$i]->date!="") {
998 $itemDate = new FeedDate($this->items[$i]->date);
999 $feed.= " <pubDate>".htmlspecialchars($itemDate->rfc822())."</pubDate>\n";
1000 }
1001 if ($this->items[$i]->guid!="") {
1002 $feed.= " <guid>".htmlspecialchars($this->items[$i]->guid)."</guid>\n";
1003 }
1004 $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " ");
1005 $feed.= " </item>\n";
1006 }
1007 $feed.= " </channel>\n";
1008 $feed.= "</rss>\n";
1009 return $feed;
1010 }
1011 }
1012
1013
1014
1015 /**
1016 * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0.
1017 *
1018 * @see http://backend.userland.com/rss
1019 * @since 1.3
1020 * @author Kai Blankenhorn <kaib@bitfolge.de>
1021 */
1022 class RSSCreator20 extends RSSCreator091 {
1023
1024 function RSSCreator20() {
1025 parent::_setRSSVersion("2.0");
1026 }
1027
1028 }
1029
1030
1031 /**
1032 * PIECreator01 is a FeedCreator that implements the emerging PIE specification,
1033 * as in http://intertwingly.net/wiki/pie/Syntax.
1034 *
1035 * @deprecated
1036 * @since 1.3
1037 * @author Scott Reynen <scott@randomchaos.com> and Kai Blankenhorn <kaib@bitfolge.de>
1038 */
1039 class PIECreator01 extends FeedCreator {
1040
1041 function PIECreator01() {
1042 $this->encoding = "utf-8";
1043 }
1044
1045 function createFeed() {
1046 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1047 $feed.= $this->_createStylesheetReferences();
1048 $feed.= "<feed version=\"0.1\" xmlns=\"http://example.com/newformat#\">\n";
1049 $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
1050 $this->truncSize = 500;
1051 $feed.= " <subtitle>".$this->getDescription()."</subtitle>\n";
1052 $feed.= " <link>".$this->link."</link>\n";
1053 for ($i=0;$i<count($this->items);$i++) {
1054 $feed.= " <entry>\n";
1055 $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
1056 $feed.= " <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
1057 $itemDate = new FeedDate($this->items[$i]->date);
1058 $feed.= " <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1059 $feed.= " <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1060 $feed.= " <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1061 $feed.= " <id>".htmlspecialchars($this->items[$i]->guid)."</id>\n";
1062 if ($this->items[$i]->author!="") {
1063 $feed.= " <author>\n";
1064 $feed.= " <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1065 if ($this->items[$i]->authorEmail!="") {
1066 $feed.= " <email>".$this->items[$i]->authorEmail."</email>\n";
1067 }
1068 $feed.=" </author>\n";
1069 }
1070 $feed.= " <content type=\"text/html\" xml:lang=\"en-us\">\n";
1071 $feed.= " <div xmlns=\"http://www.w3.org/1999/xhtml\">".$this->items[$i]->getDescription()."</div>\n";
1072 $feed.= " </content>\n";
1073 $feed.= " </entry>\n";
1074 }
1075 $feed.= "</feed>\n";
1076 return $feed;
1077 }
1078 }
1079
1080
1081 /**
1082 * AtomCreator03 is a FeedCreator that implements the atom specification,
1083 * as in http://www.intertwingly.net/wiki/pie/FrontPage.
1084 * Please note that just by using AtomCreator03 you won't automatically
1085 * produce valid atom files. For example, you have to specify either an editor
1086 * for the feed or an author for every single feed item.
1087 *
1088 * Some elements have not been implemented yet. These are (incomplete list):
1089 * author URL, item author's email and URL, item contents, alternate links,
1090 * other link content types than text/html. Some of them may be created with
1091 * AtomCreator03::additionalElements.
1092 *
1093 * @see FeedCreator#additionalElements
1094 * @since 1.6
1095 * @author Kai Blankenhorn <kaib@bitfolge.de>, Scott Reynen <scott@randomchaos.com>
1096 */
1097 class AtomCreator03 extends FeedCreator {
1098
1099 function AtomCreator03() {
1100 $this->contentType = "application/atom+xml";
1101 $this->encoding = "utf-8";
1102 }
1103
1104 function createFeed() {
1105 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1106 $feed.= $this->_createGeneratorComment();
1107 $feed.= $this->_createStylesheetReferences();
1108 $feed.= "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\"";
1109 if ($this->language!="") {
1110 $feed.= " xml:lang=\"".$this->language."\"";
1111 }
1112 $feed.= ">\n";
1113 $feed.= " <title>".htmlspecialchars($this->title)."</title>\n";
1114 $feed.= " <tagline>".htmlspecialchars($this->description)."</tagline>\n";
1115 $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link)."\"/>\n";
1116 $feed.= " <id>".htmlspecialchars($this->link)."</id>\n";
1117 $now = new FeedDate();
1118 $feed.= " <modified>".htmlspecialchars($now->iso8601())."</modified>\n";
1119 if ($this->editor!="") {
1120 $feed.= " <author>\n";
1121 $feed.= " <name>".$this->editor."</name>\n";
1122 if ($this->editorEmail!="") {
1123 $feed.= " <email>".$this->editorEmail."</email>\n";
1124 }
1125 $feed.= " </author>\n";
1126 }
1127 $feed.= " <generator>".FEEDCREATOR_VERSION."</generator>\n";
1128 $feed.= $this->_createAdditionalElements($this->additionalElements, " ");
1129 for ($i=0;$i<count($this->items);$i++) {
1130 $feed.= " <entry>\n";
1131 $feed.= " <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n";
1132 $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
1133 if ($this->items[$i]->date=="") {
1134 $this->items[$i]->date = time();
1135 }
1136 $itemDate = new FeedDate($this->items[$i]->date);
1137 $feed.= " <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
1138 $feed.= " <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
1139 $feed.= " <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
1140 $feed.= " <id>".htmlspecialchars($this->items[$i]->link)."</id>\n";
1141 $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " ");
1142 if ($this->items[$i]->author!="") {
1143 $feed.= " <author>\n";
1144 $feed.= " <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
1145 $feed.= " </author>\n";
1146 }
1147 if ($this->items[$i]->description!="") {
1148 $feed.= " <summary>".htmlspecialchars($this->items[$i]->description)."</summary>\n";
1149 }
1150 $feed.= " </entry>\n";
1151 }
1152 $feed.= "</feed>\n";
1153 return $feed;
1154 }
1155 }
1156
1157
1158 /**
1159 * MBOXCreator is a FeedCreator that implements the mbox format
1160 * as described in http://www.qmail.org/man/man5/mbox.html
1161 *
1162 * @since 1.3
1163 * @author Kai Blankenhorn <kaib@bitfolge.de>
1164 */
1165 class MBOXCreator extends FeedCreator {
1166
1167 function MBOXCreator() {
1168 $this->contentType = "text/plain";
1169 $this->encoding = "ISO-8859-15";
1170 }
1171
1172 function qp_enc($input = "", $line_max = 76) {
1173 $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1174 $lines = preg_split("/(?:\r\n|\r|\n)/", $input);
1175 $eol = "\r\n";
1176 $escape = "=";
1177 $output = "";
1178 while( list(, $line) = each($lines) ) {
1179 //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary
1180 $linlen = strlen($line);
1181 $newline = "";
1182 for($i = 0; $i < $linlen; $i++) {
1183 $c = substr($line, $i, 1);
1184 $dec = ord($c);
1185 if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only
1186 $c = "=20";
1187 } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
1188 $h2 = floor($dec/16); $h1 = floor($dec%16);
1189 $c = $escape.$hex["$h2"].$hex["$h1"];
1190 }
1191 if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
1192 $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
1193 $newline = "";
1194 }
1195 $newline .= $c;
1196 } // end of for
1197 $output .= $newline.$eol;
1198 }
1199 return trim($output);
1200 }
1201
1202
1203 /**
1204 * Builds the MBOX contents.
1205 * @return string the feed's complete text
1206 */
1207 function createFeed() {
1208 for ($i=0;$i<count($this->items);$i++) {
1209 if ($this->items[$i]->author!="") {
1210 $from = $this->items[$i]->author;
1211 } else {
1212 $from = $this->title;
1213 }
1214 $itemDate = new FeedDate($this->items[$i]->date);
1215 $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n";
1216 $feed.= "Content-Type: text/plain;\n";
1217 $feed.= " charset=\"".$this->encoding."\"\n";
1218 $feed.= "Content-Transfer-Encoding: quoted-printable\n";
1219 $feed.= "Content-Type: text/plain\n";
1220 $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n";
1221 $feed.= "Date: ".$itemDate->rfc822()."\n";
1222 $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n";
1223 $feed.= "\n";
1224 $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description));
1225 $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body);
1226 $feed.= "\n";
1227 $feed.= "\n";
1228 }
1229 return $feed;
1230 }
1231
1232 /**
1233 * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types.
1234 * @return string the feed cache filename
1235 * @since 1.4
1236 * @access private
1237 */
1238 function _generateFilename() {
1239 $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1240 return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox";
1241 }
1242 }
1243
1244
1245 /**
1246 * OPMLCreator is a FeedCreator that implements OPML 1.0.
1247 *
1248 * @see http://opml.scripting.com/spec
1249 * @author Dirk Clemens, Kai Blankenhorn
1250 * @since 1.5
1251 */
1252 class OPMLCreator extends FeedCreator {
1253
1254 function OPMLCreator() {
1255 $this->encoding = "cp1250";
1256 }
1257
1258 function createFeed() {
1259 $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
1260 $feed.= $this->_createGeneratorComment();
1261 $feed.= $this->_createStylesheetReferences();
1262 $feed.= "<opml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
1263 $feed.= " <head>\n";
1264 $feed.= " <title>".htmlspecialchars($this->title)."</title>\n";
1265 if ($this->pubDate!="") {
1266 $date = new FeedDate($this->pubDate);
1267 $feed.= " <dateCreated>".$date->rfc822()."</dateCreated>\n";
1268 }
1269 if ($this->lastBuildDate!="") {
1270 $date = new FeedDate($this->lastBuildDate);
1271 $feed.= " <dateModified>".$date->rfc822()."</dateModified>\n";
1272 }
1273 if ($this->editor!="") {
1274 $feed.= " <ownerName>".$this->editor."</ownerName>\n";
1275 }
1276 if ($this->editorEmail!="") {
1277 $feed.= " <ownerEmail>".$this->editorEmail."</ownerEmail>\n";
1278 }
1279 $feed.= " </head>\n";
1280 $feed.= " <body>\n";
1281 for ($i=0;$i<count($this->items);$i++) {
1282 $feed.= " <outline type=\"rss\" ";
1283 $title = htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")));
1284 $feed.= " title=\"".$title."\"";
1285 $feed.= " text=\"".$title."\"";
1286 //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\"";
1287 $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\"";
1288 $feed.= "/>\n";
1289 }
1290 $feed.= " </body>\n";
1291 $feed.= "</opml>\n";
1292 return $feed;
1293 }
1294 }
1295
1296
1297
1298 /**
1299 * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific
1300 * location, overriding the createFeed method of the parent FeedCreator.
1301 * The HTML produced can be included over http by scripting languages, or serve
1302 * as the source for an IFrame.
1303 * All output by this class is embedded in <div></div> tags to enable formatting
1304 * using CSS.
1305 *
1306 * @author Pascal Van Hecke
1307 * @since 1.7
1308 */
1309 class HTMLCreator extends FeedCreator {
1310
1311 var $contentType = "text/html";
1312
1313 /**
1314 * Contains HTML to be output at the start of the feed's html representation.
1315 */
1316 var $header;
1317
1318 /**
1319 * Contains HTML to be output at the end of the feed's html representation.
1320 */
1321 var $footer ;
1322
1323 /**
1324 * Contains HTML to be output between entries. A separator is only used in
1325 * case of multiple entries.
1326 */
1327 var $separator;
1328
1329 /**
1330 * Used to prefix the stylenames to make sure they are unique
1331 * and do not clash with stylenames on the users' page.
1332 */
1333 var $stylePrefix;
1334
1335 /**
1336 * Determines whether the links open in a new window or not.
1337 */
1338 var $openInNewWindow = true;
1339
1340 var $imageAlign ="right";
1341
1342 /**
1343 * In case of very simple output you may want to get rid of the style tags,
1344 * hence this variable. There's no equivalent on item level, but of course you can
1345 * add strings to it while iterating over the items ($this->stylelessOutput .= ...)
1346 * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored
1347 * in the function createFeed().
1348 */
1349 var $stylelessOutput ="";
1350
1351 /**
1352 * Writes the HTML.
1353 * @return string the scripts's complete text
1354 */
1355 function createFeed() {
1356 // if there is styleless output, use the content of this variable and ignore the rest
1357 if ($this->stylelessOutput!="") {
1358 return $this->stylelessOutput;
1359 }
1360
1361 //if no stylePrefix is set, generate it yourself depending on the script name
1362 if ($this->stylePrefix=="") {
1363 $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_";
1364 }
1365
1366 //set an openInNewWindow_token_to be inserted or not
1367 if ($this->openInNewWindow) {
1368 $targetInsert = " target='_blank'";
1369 }
1370
1371 // use this array to put the lines in and implode later with "document.write" javascript
1372 $feedArray = array();
1373 if ($this->image!=null) {
1374 $imageStr = "<a href='".$this->image->link."'".$targetInsert.">".
1375 "<img src='".$this->image->url."' border='0' alt='".
1376 FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
1377 "' align='".$this->imageAlign."' ";
1378 if ($this->image->width) {
1379 $imageStr .=" width='".$this->image->width. "' ";
1380 }
1381 if ($this->image->height) {
1382 $imageStr .=" height='".$this->image->height."' ";
1383 }
1384 $imageStr .="/></a>";
1385 $feedArray[] = $imageStr;
1386 }
1387
1388 if ($this->title) {
1389 $feedArray[] = "<div class='".$this->stylePrefix."title'><a href='".$this->link."' ".$targetInsert." class='".$this->stylePrefix."title'>".
1390 FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</a></div>";
1391 }
1392 if ($this->getDescription()) {
1393 $feedArray[] = "<div class='".$this->stylePrefix."description'>".
1394 str_replace("]]>", "", str_replace("<![CDATA[", "", $this->getDescription())).
1395 "</div>";
1396 }
1397
1398 if ($this->header) {
1399 $feedArray[] = "<div class='".$this->stylePrefix."header'>".$this->header."</div>";
1400 }
1401
1402 for ($i=0;$i<count($this->items);$i++) {
1403 if ($this->separator and $i > 0) {
1404 $feedArray[] = "<div class='".$this->stylePrefix."separator'>".$this->separator."</div>";
1405 }
1406
1407 if ($this->items[$i]->title) {
1408 if ($this->items[$i]->link) {
1409 $feedArray[] =
1410 "<div class='".$this->stylePrefix."item_title'><a href='".$this->items[$i]->link."' class='".$this->stylePrefix.
1411 "item_title'".$targetInsert.">".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
1412 "</a></div>";
1413 } else {
1414 $feedArray[] =
1415 "<div class='".$this->stylePrefix."item_title'>".
1416 FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
1417 "</div>";
1418 }
1419 }
1420 if ($this->items[$i]->getDescription()) {
1421 $feedArray[] =
1422 "<div class='".$this->stylePrefix."item_description'>".
1423 str_replace("]]>", "", str_replace("<![CDATA[", "", $this->items[$i]->getDescription())).
1424 "</div>";
1425 }
1426 }
1427 if ($this->footer) {
1428 $feedArray[] = "<div class='".$this->stylePrefix."footer'>".$this->footer."</div>";
1429 }
1430
1431 $feed= "".join($feedArray, "\r\n");
1432 return $feed;
1433 }
1434
1435 /**
1436 * Overrrides parent to produce .html extensions
1437 *
1438 * @return string the feed cache filename
1439 * @since 1.4
1440 * @access private
1441 */
1442 function _generateFilename() {
1443 $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1444 return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html";
1445 }
1446 }
1447
1448
1449 /**
1450 * JSCreator is a class that writes a js file to a specific
1451 * location, overriding the createFeed method of the parent HTMLCreator.
1452 *
1453 * @author Pascal Van Hecke
1454 */
1455 class JSCreator extends HTMLCreator {
1456 var $contentType = "text/javascript";
1457
1458 /**
1459 * writes the javascript
1460 * @return string the scripts's complete text
1461 */
1462 function createFeed()
1463 {
1464 $feed = parent::createFeed();
1465 $feedArray = explode("\n",$feed);
1466
1467 $jsFeed = "";
1468 foreach ($feedArray as $value) {
1469 $jsFeed .= "document.write('".trim(addslashes($value))."');\n";
1470 }
1471 return $jsFeed;
1472 }
1473
1474 /**
1475 * Overrrides parent to produce .js extensions
1476 *
1477 * @return string the feed cache filename
1478 * @since 1.4
1479 * @access private
1480 */
1481 function _generateFilename() {
1482 $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
1483 return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js";
1484 }
1485
1486 }
1487
1488
1489
1490 /*** TEST SCRIPT *********************************************************
1491
1492 //include("feedcreator.class.php");
1493
1494 $rss = new UniversalFeedCreator();
1495 $rss->useCached();
1496 $rss->title = "PHP news";
1497 $rss->description = "daily news from the PHP scripting world";
1498
1499 //optional
1500 //$rss->descriptionTruncSize = 500;
1501 //$rss->descriptionHtmlSyndicated = true;
1502 //$rss->xslStyleSheet = "http://feedster.com/rss20.xsl";
1503
1504 $rss->link = "http://www.dailyphp.net/news";
1505 $rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF;
1506
1507 $image = new FeedImage();
1508 $image->title = "dailyphp.net logo";
1509 $image->url = "http://www.dailyphp.net/images/logo.gif";
1510 $image->link = "http://www.dailyphp.net";
1511 $image->description = "Feed provided by dailyphp.net. Click to visit.";
1512
1513 //optional
1514 $image->descriptionTruncSize = 500;
1515 $image->descriptionHtmlSyndicated = true;
1516
1517 $rss->image = $image;
1518
1519 // get your news items from somewhere, e.g. your database:
1520 //mysql_select_db($dbHost, $dbUser, $dbPass);
1521 //$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");
1522 //while ($data = mysql_fetch_object($res)) {
1523 $item = new FeedItem();
1524 $item->title = "This is an the test title of an item";
1525 $item->link = "http://localhost/item/";
1526 $item->description = "<b>description in </b><br/>HTML";
1527
1528 //optional
1529 //item->descriptionTruncSize = 500;
1530 $item->descriptionHtmlSyndicated = true;
1531
1532 $item->date = time();
1533 $item->source = "http://www.dailyphp.net";
1534 $item->author = "John Doe";
1535
1536 $rss->addItem($item);
1537 //}
1538
1539 // valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS
1540 echo $rss->saveFeed("RSS0.91", "feed.xml");
1541
1542
1543
1544 ***************************************************************************/
1545
1546 ?>
This page took 2.592542 seconds and 4 git commands to generate.