5 // +----------------------------------------------------------------------+
7 // | Copyright (c) 2001 Stefan Saasen |
8 // +----------------------------------------------------------------------+
9 // | The contents of this file are subject to the Mozilla Public License |
10 // | Version 1.1 (the "License"); you may not use this file except in |
11 // | compliance with the License. You may obtain a copy of the License at |
12 // | http://www.mozilla.org/MPL/ |
14 // | Software distributed under the License is distributed on an "AS IS" |
15 // | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
16 // | the License for the specific language governing rights and |
17 // | limitations under the License. |
18 // +----------------------------------------------------------------------+
20 // | Maintainer and initial developer: |
21 // | Stefan Saasen <s@fase4.com> |
23 // | Proxy and authentication methods added by: |
24 // | Marco Kraus <marco.kraus@siemens.com> |
26 // | Decoding of data by htmlentities or utf8_decode added by: |
27 // | Roland Haeder <webmaster@mxchange.org> |
29 // +----------------------------------------------------------------------+
31 // | @link http://www.fase4.com/rdf/ Latest release |
32 // +----------------------------------------------------------------------+
37 * This class offers methods to parse RSS Files
39 * @link http://www.fase4.com/rdf/ Latest release of this class
41 * @copyright Copyright (c) 2001 fase4.com. All rights reserved.
42 * @author Stefan Saasen <s@fase4.com>
43 * @author Roland Haeder <webmaster@mxchange.org>
44 * @version 1.7 ($Date$Revision: 856 $
51 * Word-wrapping mode for description, set it to 0 do disable this feature! Ommits _use_nl2br!
56 var $_word_wrap = '0';
59 * Wether to recode \n -> <br /> or not in description
64 var $_use_nl2br = true;
67 * Sets the decoding mode of the read data (UTF8 scrambles some german umlauts here!)
69 * "htmlentities" - Use the function htmlentities()
70 * "utf8_decode" - Use the function ut8_decode() when you have UTF8 encoded text
71 * <empty> - Use non of both
76 var $_decoding_mode = '';
79 * If $_link_target is set a target='xxx' attribute in each <a /> and <form accept-charset="utf-8" /> html tag will be added
81 * Possible values are "_blank", "_content", "_parent", "_self", "_top"
86 var $_link_target = '_blank';
89 * vars for proxy settings - Prox Host
97 * vars for proxy settings - Prox Port
105 * vars for proxy settings - Prox Username
113 * vars for proxy settings - Prox Password
121 * just a flag for checking if proxy-support should be enabled
122 * set default to false (will be enabled if set_proxy is called)
128 var $_use_proxy = false;
131 * just a flag for checking if proxy-support with authentication
133 * set default to false (will be enabled if set_proxy is called)
139 var $_use_proxy_auth = false;
142 * The time the Files will be cached (in seconds).
147 var $_refresh = 60; // int
150 * The Name of the cached File.
155 var $_cached_file = ''; // String
158 * Indicates whether the cached or the remote file was used.
163 var $_use_cached_file = true;
166 * (fast|normal) depends on _use_dynamic_display(). _use_dynamic_display( TRUE ) -> 'normal', otherwise 'fast'
171 var $_cache_type = 'fast';
174 * The Name of the Remote File.
179 var $_remote_file = '';
182 * Path to the Cache Directory.
187 var $_cache_dir = 'cache/'; // String
190 * Indicates whether the Creating of the Cache Directory needs to be done or not.
195 var $_cache_dir_ok = false;
198 * Type of the file to be parsed (RSS or RDF).
200 * The Type depends on the root node
205 var $_type = 'rss'; // string (rss or rdf)
208 * Array of Display Settings.
210 * Specific Parameters can be set to hidden. These are:
211 * image, channel and textinput. If set to "hidden" those elements won't be displayed.
216 var $_display_opt = array(
221 'cache_update' => '',
228 * Defines the width attribute in the table that holds the rdf/rss representation
232 * @see see_table_width()
234 var $_table_width = '100%';
237 * Indicates whether or not to use dynamic Display Settings
242 var $_use_dynamic_display = false;
250 var $_item_count = '0';
258 var $_max_count = false;
261 * Array containing the content of <channel />
266 var $_array_channel = array();
269 * Array containing the content of each <item />
274 var $_array_item = array();
277 * Array containing the content of <textinput />
282 var $_array_textinput = array();
285 * Array containing the content of <image />
290 var $_array_image = array();
293 * Array containing the Channel content. Just For internal XML Parser Purposes.
298 var $_citem = array();
301 * Array containing the Channel Parser Depth. Just For internal XML Parser Purposes.
306 var $_cdepth = array();
309 * Array containing the Channel tags. Just For internal XML Parser Purposes.
314 var $_ctags = array( 'x' );
317 * Array containing the Channel content. Just For internal XML Parser Purposes.
322 var $_item = array(); // Array
325 * Array containing the Channel Parser Depth. Just For internal XML Parser Purposes.
330 var $_depth = array(); // Array
333 * Array containing the tags. Just For internal XML Parser Purposes.
338 var $_tags = array( 'x' ); // Array
341 * Garbage collection: probability in percent
343 * @var integer 0 => never
346 var $gc_probability = 1;
359 var $_parse_mode = '';
368 * Constructor of our Class
370 * This Method checks if the Cache Directory can be found. Otherwise it tries to creat the Cache Directory at the specified Path.
371 * Additionally the Refresh Time is set to a default Value of 1200s (20 min).
374 * @author Stefan Saasen <s@fase4.com>
379 // default Value, to be overwritten in set_refresh()
380 $this->_refresh = (time() - 1200);
381 $this->_clear_cItems();
382 $this->_clear_Items();
386 * This Method starts the parsing of the specified RDF File. The File can be a local or a remote File.
389 * @author Stefan Saasen <s@fase4.com>
390 * @param string $rdf RDF File (Location)
391 * @return string Displays RDF Content ( using _display() )
392 * @see _remote_file, cache()
394 function parse_RDF( $rdf )
396 unset($this->_array_item);
397 $this->_remote_file = $rdf;
398 $this->out .= "<!-- http://www.fase4.com/rdf/ -->";
399 $this->out .= "<table width=\"".$this->_table_width."\">";
400 $this->out .= $this->cache();
401 $this->out .= "</table>";
403 $this->_item_count = '0';
408 * This Method is called when all parsing is finished to use the garbage collection
411 * @author Stefan Saasen <s@fase4.com>
412 * @param string $rdf RDF File (Location)
413 * @return string Displays RDF Content ( using _display() )
414 * @see _remote_file, cache()
416 function finish($return = false)
418 $this->out = str_replace('$', '$', $this->out);
425 $this->_garbage_collection();
429 * With this method you can decide whether to use the normal cache and dynamic display Options or to use a static cache.
431 * In the first case the rdf/rss File will be stored locally, in the second case the html output of the specified source will be stored.
432 * In this case you can not modify the display settings.
433 * processing time: ( 1.4792) --> remote file
434 * processing time: ( 0.0313) --> using 'normal cache' with display Modification turned on.
435 * processing time: ( 0.0019) --> using 'fast cache'
438 * @author Stefan Saasen <s@fase4.com>
439 * @param string $rdf RDF File (Location)
440 * @return string Displays RDF Content ( using _display() )
441 * @see _remote_file, cache()
443 function use_dynamic_display( $bool )
445 $this->_use_dynamic_display = $bool;
450 * This Method avtually parses the XML data.
453 * @author Stefan Saasen <s@fase4.com>
454 * @param string $data RDF File XML Data
455 * @see _clear_Items()
457 function _parse_xRDF( $data )
459 $this->_clear_Items();
460 $xml_parser = xml_parser_create();
461 xml_set_object($xml_parser,$this);
462 xml_parser_set_option($xml_parser,XML_OPTION_CASE_FOLDING,0);
463 xml_set_element_handler($xml_parser, '_startElement', '_endElement');
464 xml_set_character_data_handler($xml_parser, '_parseData');
465 if (!xml_parse($xml_parser, trim($data))) {
466 $this->_throw_exception(sprintf("XML error: %s at line %d",
467 xml_error_string(xml_get_error_code($xml_parser)),
468 xml_get_current_line_number($xml_parser)).'<br /><br />Exception in function parse_RDF().');
470 xml_parser_free($xml_parser);
475 * This Methods allows you to set the Refresh Time
478 * @author Stefan Saasen <s@fase4.com>
479 * @param int $seconds time files will be cached (in seconds).
483 function set_refresh( $seconds )
485 $this->_refresh = (time() - $seconds);
489 function set_salt( $saltPara )
491 $this->salt = $saltPara;
496 * This Methods allows you to set the No. of <item>s to display
499 * @param int $int No of max <item>s
500 * @author Stefan Saasen <s@fase4.com>
502 * @see _max_count, _endElement()
504 function set_max_item( $int )
506 $this->_max_count = $int;
511 * This Methods allows you to set the Cache Directory
514 * @author Stefan Saasen <s@fase4.com>
515 * @param string $dir Path to Directory.
519 function set_CacheDir( $dir )
521 if(substr($dir, -1) != '/') {
524 $this->_cache_dir = $dir;
528 * This Method displays Error Messages and terminates the Execution of the Script
531 * @param string $msg Message to display on failure
532 * @author Stefan Saasen <s@fase4.com>
534 function _throw_exception( $msg )
536 $this->out .= "<div style=\"font-family: verdana, helvetica, arial, sans-serif;font-size:11px; color: #6699cc;margin-top:10px;margin-bottom:10px;\" align=\"center\">fase4 RDF Error: ".$msg."</div>";
541 * This Method clears the Array containig the Items.
544 * @author Stefan Saasen <s@fase4.com>
547 function _clear_Items( ) {
548 $this->_item = array(
555 'lastBuildDate' => '',
561 * This Method clears the Array containig the Channel Items.
564 * @author Stefan Saasen <s@fase4.com>
567 function _clear_cItems( ) {
568 $this->_citem = array(
575 'managingEditor' => '',
578 'lastBuildDate' => '',
595 * XML Parser Start Element Handler
598 * @author Stefan Saasen <s@fase4.com>
599 * @param mixed $parser a reference to the XML parser calling the handler.
600 * @param string $name contains the name of the element for which this handler is called.
601 * @param string $attrs contains an associative array with the element's attributes (if any).
602 * @see _get_ChannelData(), _clear_Items(), _type, _parse_mode, _depth, _tags, _cdepth, _ctags
604 function _startElement($parser, $name, $attrs) {
605 // We have to determine, which type of xml data we have to parse
607 $this->_type = 'rss';
608 } elseif($name == 'rdf:RDF' OR $name == 'rdf') {
609 $this->_type = 'rdf';
613 if ( $name == 'channel' AND $this->_type != 'rdf' ) {
614 $this->_parse_mode = 'channel';
615 } elseif ( ($name=='item')
617 ||($name=='textinput')
618 ||(($name=='channel') && ($this->_type != 'rss')) ) {
619 if($this->_parse_mode=='channel') {
620 $this->_get_ChannelData( $parser );
622 $this->_parse_mode = 'all';
625 if( !isset( $this->_depth[$this->get_parser_id($parser)] ) ) {
626 $this->_depth[$this->get_parser_id($parser)] = '0';
628 $this->_depth[$this->get_parser_id($parser)]++;
629 array_push($this->_tags, $name);
631 if( !isset( $this->_cdepth[$this->get_parser_id($parser)] ) ) {
632 $this->_cdepth[$this->get_parser_id($parser)] = '0';
634 $this->_cdepth[$this->get_parser_id($parser)]++;
635 array_push($this->_ctags, $name);
636 } // END _startElement()
639 * Retrives the Channel Data in <rss> File
642 * @author Stefan Saasen <s@fase4.com>
643 * @param mixed $parser a reference to the XML parser calling the handler.
644 * @see _output, _display_opt, _citem
646 function _get_ChannelData( $parser )
648 $this->_citem['link'] = trim($this->_citem['link']);
649 if (($this->_display_opt['sitelink'] == $this->_citem['link']) && (!empty($this->_display_opt['reflink'])) && (!empty($this->_display_opt['refid'])))
651 $this->_citem['link'] .= $this->_display_opt['reflink'].$this->_display_opt['refid'];
654 if( empty($this->_display_opt['channel']) OR
655 $this->_display_opt['channel'] != 'hidden') {
656 $this->_output .= "<tr><td>\n";
657 $this->_output .= "<table border=\"0\" width=\"100%\" class=\"fase4_rdf_meta\" cellspacing=\"5\" cellpadding=\"2\">\n";
658 $this->_output .= "<tr><td class=\"fase4_rdf_main_title\"><div class=\"fase4_rdf_main_title\">".htmlspecialchars($this->_citem['title'])."</div></td></tr>\n";
659 $this->_output .= "<tr><td class=\"fase4_rdf\">".strip_tags($this->_citem['description'], '<a>, <img>')."</td></tr>\n";
660 $this->_output .= "<tr><td> </td></tr>\n";
661 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
662 if(isset($this->_display_opt['build']) && $this->_display_opt['build'] != 'hidden') {
663 if($this->_citem['lastBuildDate']){$this->_output .= 'build: '. $this->_citem['lastBuildDate'].'<br />';}
665 if(isset($this->_display_opt['cache_update']) && $this->_display_opt['cache_update'] != 'hidden' && ( $_update = $this->get_cache_update_time()) ) {
666 $this->_output .= 'cache update: '.$_update."<br />\n";
668 $this->_output .= "<a href=\"".$this->_citem['link']."\" ";
669 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
670 $this->_output .= ">".$this->_cut_string($this->_citem['link']) . '</a>';
671 $this->_output .= "</td></tr>\n";
672 $this->_output .= "<tr><td><hr noshade width=\"100%\" size=\"1\"></td></tr>\n";
673 $this->_output .= "</table></td></tr>";
675 $this->_array_channel = array(
676 'title' => $this->_citem['title'],
677 'link' => $this->_citem['link'],
678 'description' => $this->_citem['description'],
679 'lastBuildDate' => $this->_citem['lastBuildDate']);
683 * XML Parser End Element Handler
686 * @author Stefan Saasen <s@fase4.com>
687 * @param mixed $parser a reference to the XML parser calling the handler.
688 * @param string $name contains the name of the element for which this handler is called.
689 * @see _clear_Items(), _type, _parse_mode, _depth, _tags, _cdepth, _ctags, _item, _output, _display_opt
691 function _endElement($parser, $name) {
692 array_pop($this->_tags);
693 $this->_depth[$this->get_parser_id($parser)]--;
694 array_pop($this->_ctags);
695 $this->_cdepth[$this->get_parser_id($parser)]--;
696 $this->_item['link'] = trim($this->_item['link']);
697 if ((!empty($this->_display_opt['refid'])) && (!empty($this->_item['link'])))
699 if (!isInString('refid=', $this->_item['link'])) $this->_item['link'] .= '?refid=' . $this->_display_opt['refid'];
703 if(empty($this->_max_count) OR $this->_item_count < $this->_max_count) {
704 if($this->_item['title'] != $this->_item['description']
705 AND $this->_item['description']) {
707 // word-wrapping added by Roland Haeder <webmaster@mxchange.org>
708 if (($this->_word_wrap > 0) && (strlen($this->_item['description']) > $this->_word_wrap))
710 // Switch off _use_nl2br
711 $this->_use_nl2br = false;
712 // First remove all \n
713 $this->_item['description'] = str_replace('\n', ' ', $this->_item['description']);
714 // Wrap with <br />\n
715 $this->_item['description'] = wordwrap($this->_item['description'], $this->_word_wrap, "*<br />\n");
717 elseif (($this->_word_wrap == '0') && (!$this->_use_nl2br))
719 // Strip tags out instead when word-wrap is disabled
720 $this->_item['description'] = strip_tags($this->_item['description'], '<a>, <img>');
723 // nl2br added by Roland Haeder <webmaster@mxchange.org>
724 if ($this->_use_nl2br) $this->_item['description'] = nl2br($this->_item['description']);
726 $this->_output .= "<tr><td class=\"fase4_rdf_title\"><div class=\"fase4_rdf_title\"><a class=\"fase4_rdf_title\" href=\"".$this->_item['link']."\" ";
727 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
728 $this->_output .= ">".strip_tags($this->_item['title'], '<a>, <img>').'</a> ('.$this->_item['pubDate'].")</div></td></tr>\n";
729 $this->_output .= "<tr><td class=\"fase4_rdf\">".$this->_item['description']."</td></tr>\n";
730 // we just display the <hr> if there is a description
731 $this->_output .= "<tr><td><hr noshade=\"noshade\" size=\"1\" /></td></tr>\n";
733 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
734 $this->_output .= "<a href=\"".$this->_item["link"]."\" ";
735 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
736 $this->_output .= ">".$this->_item["title"]."</a></td></tr>\n";
739 $this->_array_item[] = array(
740 'title' => $this->_item['title'],
741 'link' => $this->_item['link'],
742 'description' => $this->_item['description']
745 ++$this->_item_count;
747 $this->_clear_Items();
751 if(isset($this->_display_opt['image']) && ($this->_display_opt['image'] != 'hidden') && $this->_item['url']) {
752 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
753 $this->_output .= "<a href=\"".$this->_item['link']."\" ";
754 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
755 $this->_output .= "><img src=\"".$this->_item['url']."\"";
756 if(isset($this->_item['width']) && isset($this->_item['height'])) {
757 $this->_output .= " width=\"".$this->_item['width']."\" height=\"".$this->_item['height']."\"";
759 $this->_output .= " alt=\"".$this->_item['title']."\" border=\"0\" /></a></td></tr>\n";
761 $this->_array_image[] = array(
762 'url' => $this->_item['url'],
763 'link' => $this->_item['link'],
764 'width' => $this->_item['width'],
765 'height' => $this->_item['height']
767 $this->_clear_Items();
768 } elseif( isset($this->_display_opt['image'] ) && ($this->_display_opt['image'] == 'hidden') ) {
769 $this->_clear_Items();
775 if(isset($this->_display_opt['channel']) AND $this->_display_opt['channel'] != 'hidden' AND $this->_item['title'] != '') {
776 $this->_output .= "<tr><td>\n";
777 $this->_output .= "<table border=\"0\" width=\"100%\" class=\"fase4_rdf_meta\" cellspacing=\"5\" cellpadding=\"2\">\n";
778 $this->_output .= "<tr><td class=\"fase4_rdf\"><div class=\"fase4_rdf_title\">".htmlspecialchars($this->_item['title'])."</div></td></tr>\n";
779 $this->_output .= "<tr><td class=\"fase4_rdf\">".strip_tags($this->_item['description'], '<a>, <img>')."</td></tr>\n";
780 $this->_output .= "<tr><td> </td></tr>\n";
781 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
782 if($this->_display_opt['build'] != 'hidden') {
783 if($this->_item['lastBuildDate']){$this->_output .= 'build: '. $this->_item['lastBuildDate'].'<br />';}
785 if($this->_display_opt['cache_update'] != 'hidden' && ( $_update = $this->get_cache_update_time()) ) {
786 $this->_output .= 'cache update: '.$_update."<br />\n";
788 $this->_output .= "<a href=\"".$this->_item['link']."\" ";
789 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
790 $this->_output .= ">".$this->_cut_string($this->_item['link'])."</a>\n";
791 $this->_output .= "</td></tr>\n";
792 $this->_output .= "</table></td></tr>\n";
794 $this->_array_channel = array(
795 'title' => $this->_item['title'],
796 'link' => $this->_item['link'],
797 'description' => $this->_item['description'],
798 'lastBuildDate' => $this->_item['lastBuildDate']
800 $this->_clear_Items();
801 $this->_clear_cItems();
805 if(isset($this->_display_opt['textinput']) && ($this->_display_opt['textinput'] != 'hidden') && $this->_item['name'] && $this->_item['link']) {
806 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
807 $this->_output .= "<form accept-charset=\"utf-8\" action=\"".$this->_item['link']."\" ";
808 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
809 $this->_output .= "method=\"get\">\n";
810 $this->_output .= "<div class=\"fase4_rdf_title\">".$this->_item['title']."</div>";
811 $this->_output .= strip_tags($this->_item['description'], '<a>, <img>')."<br /><br />\n";
812 $this->_output .= "<input class=\"fase4_rdf_input\" type=\"text\" name=\"".$this->_item['name']."\"> \n";
813 $this->_output .= "<input class=\"fase4_rdf_input\" type=\"submit\" value=\"go\">";
814 $this->_output .= "</form>\n";
815 $this->_output .= "</td></tr>\n";
816 $this->_array_textinput = array(
817 'title' => $this->_item['title'],
818 'name' => $this->_item['name'],
819 'link' => $this->_item['link'],
820 'description' => $this->_item['description']
822 $this->_clear_Items();
823 } elseif( isset($this->_display_opt['textinput']) && ($this->_display_opt['textinput'] == 'hidden') ) {
824 $this->_clear_Items();
832 * This Method returns the data from the <channel /> paragraph.
835 * @author Stefan Saasen <s@fase4.com>
837 * @see _array_channel
839 function get_array_channel( )
841 return $this->_array_channel;
845 * This Method returns the data from each <item /> paragraph.
848 * @author Stefan Saasen <s@fase4.com>
852 function get_array_item( )
854 return $this->_array_item;
858 * This Method returns the data from <textinput />.
861 * @author Stefan Saasen <s@fase4.com>
863 * @see _array_textinput
865 function get_array_textinput( )
867 return $this->_array_textinput;
871 * Getter for parser id from resource
874 * @author Roland Haeder <webmaster@mxchange.org>
877 function get_parser_id ($parser) {
882 if (is_resource($parser)) {
883 // Cast the resource into id
892 * This Method returns the data from <image />.
895 * @author Stefan Saasen <s@fase4.com>
899 function get_array_image( )
901 return $this->_array_image;
905 * XML Parser Data Handler
908 * @author Stefan Saasen <s@fase4.com>
909 * @param mixed $parser a reference to the XML parser calling the handler.
910 * @param string $text contains the character data as a string.
911 * @see _parse_mode, _item, _tags, _depth, _citem, _ctags, _cdepth
913 function _parseData($parser, $text)
915 // Deocing mode added by Roland Haeder <webmaster@mxchange.org>
916 switch ($this->_decoding_mode)
919 $text = utf8_decode($text);
923 $text = htmlentities($text);
927 $clean = preg_replace("/\s/", "", $text);
929 $text = preg_replace("/^\s+/", "", $text)."\n";
930 if($this->_parse_mode == 'all') {
931 if ( isset($this->_item[$this->_tags[$this->_depth[$this->get_parser_id($parser)]]]) &&
932 $this->_item[$this->_tags[$this->_depth[$this->get_parser_id($parser)]]] ) {
933 $this->_item[$this->_tags[$this->_depth[$this->get_parser_id($parser)]]] .= $text;
935 $this->_item[$this->_tags[$this->_depth[$this->get_parser_id($parser)]]] = $text;
937 } elseif (isset($this->_parse_mode) && $this->_parse_mode == 'channel') {
938 if ( isset($this->_citem[$this->_ctags[$this->_cdepth[$this->get_parser_id($parser)]]]) ) {
939 $this->_citem[$this->_ctags[$this->_cdepth[$this->get_parser_id($parser)]]] .= $text;
941 $this->_citem[$this->_ctags[$this->_cdepth[$this->get_parser_id($parser)]]] = $text;
948 * This Method allows you to choose if specific Parameters are displayed or not. These are:
949 * image, channel, textinput, build and cache_update. If set to "hidden" those elements won't be displayed.
952 * @author Stefan Saasen <s@fase4.com>
953 * @param array $options
956 function set_Options( $options = '' )
958 if(is_array( $options )) {
959 $this->_display_opt = $options;
962 unset($this->_display_opt);
968 * This Method allows you to define the width of the table that holds the representation of the rdf/rss file.
971 * @author Stefan Saasen <s@fase4.com>
972 * @param int $width attribute width in tag <table>
975 function set_table_width( $width = 400 )
977 $this->_table_width = $width;
982 * This Method returns an assocative Array with available Options.
984 * The Keys are the Name of the Options to be set.
985 * The Values are short Description of available Options.
988 * @author Stefan Saasen <s@fase4.com>
989 * @return array $options
992 function get_Options() {
994 'image' => "If 'image' is set to \"hidden\" no image provided by the RDF Publisher will be displayed.",
995 'channel' => "If 'channel' is set to \"hidden\" the Channel Meta Data (i.e the Title and the short description regarding the RDF Publisher will not be displayed",
996 'textinput' => "If set to \"hidden\" no Input Form will be displayed",
997 'build' => "If set to \"hidden\" the Build Date (if provided) of the RDF File will not be displayed",
998 'cache_update' => "If set to \"hidden\" the Update Date/Time of the cached Rdf File will not be displayed"
1004 * This Method returns the Content of the RDF File in one string. The String actually holds the whole XML Document.
1007 * @author Stefan Saasen <s@fase4.com>
1008 * @param string $rdf RDF File (Location)
1009 * @return string XML Presentation of parsed RDF File
1010 * @see _cached_file, _remote_file, _cache_dir, _refresh, _update_cache()
1014 // checks if the cache directory already exists
1015 // if not, the cache directory will be created
1016 if(!$this->_cache_dir_ok) {
1017 $this->_create_cache_dir();
1019 if($this->_use_dynamic_display == true) {
1020 $this->_cached_file = md5('dynamic'.$this->salt.$this->_remote_file) . '.cache';
1021 $this->_cache_type = 'normal';
1023 $this->_cached_file = md5($this->salt.$this->_remote_file) . '.cache';
1024 $this->_cache_type = 'fast';
1027 $_cache_f = $this->_cache_dir.$this->_cached_file;
1029 if ( (!file_exists($_cache_f)) || (filemtime($_cache_f) < $this->_refresh) || (filesize($_cache_f) == 0)) {
1030 // We have to parse the remote file
1031 $this->_use_cached_file = false;
1032 // --> we want to provide proper Information for Use in
1033 // get_cache_update_time()
1035 if($this->_use_dynamic_display == true) {
1036 $_rdf = @implode(' ', $this->_rdf_data()); // -> proxy
1038 $this->_throw_exception( $this->_remote_file.' is not available' );
1040 $this->_parse_xRDF( $_rdf );
1041 $this->_update_cache( $_rdf );
1042 $data = $this->_output;
1044 $_rdf = @implode(' ', $this->_rdf_data()); // -> proxy
1046 $this->_throw_exception( $this->_remote_file.' is not available' );
1048 $this->_parse_xRDF( $_rdf );
1049 $this->_update_cache( $this->_output );
1050 $data = $this->_output;
1053 // we can use the cached file
1054 $this->_use_cached_file = true;
1055 if($this->_use_dynamic_display == true) {
1056 $this->_parse_xRDF( implode(' ', file($_cache_f)) );
1057 $data = $this->_output;
1059 $data = @implode(' ', file($_cache_f));
1066 * This Methods creates the Cache Directory if the specified Directory does not exist.
1069 * @author Stefan Saasen <s@fase4.com>
1070 * @param string $dir Path to Directory.
1072 * @see _cache_dir, _cache_dir_ok
1074 function _create_cache_dir()
1077 if(!@is_dir($this->_cache_dir)) {
1078 $arr = explode('/', $this->_cache_dir);
1083 for($i = '0';$i<$c;$i++)
1086 $path .= $arr[$i].'/';
1087 if(!@is_dir($path)) {
1088 if(!@mkdir($path, 0777)) {
1089 $this->_throw_exception("failed to create directory:<b>".$this->_cache_dir."</b>.<br /><br />Exception on Line: ".__LINE__);
1095 $this->_cache_dir_ok = true;
1098 $this->_cache_dir_ok = true;
1101 } // END _create_cache_dir()
1104 * This Method updates the cached RDF Files and synchronises them with their remote Counterparts.
1107 * @author Stefan Saasen <s@fase4.com>
1108 * @param string $rdf RDF File (Location)
1109 * @see _cache_dir, _cached_file, _throw_exception()
1111 function _update_cache( $content = '' )
1113 $_local = @fopen( $this->_cache_dir.$this->_cached_file, 'w' );
1115 $this->_throw_exception( 'Cannot open '.$this->_cached_file.'<br /><br />Exception at Line: '.__LINE__ );
1118 if (fwrite( $_local, $content) === false) {
1119 $this->_throw_exception( 'Cannot write to '.$this->_cached_file.'<br /<br />Exeception at Line: '.__LINE__);
1123 @chmod( $this->_cache_dir.$this->_cached_file, 0666);
1125 } // END _update_cache()
1128 * This Method returns the Date/Time of last Cache Update of the actually parsed RDF File.
1131 * @author Stefan Saasen <s@fase4.com>
1132 * @return string Date/Time of last Update
1133 * @see _cache_dir, _cached_file
1135 function get_cache_update_time()
1137 return (file_exists($this->_cache_dir.$this->_cached_file))?date('d.m.Y H:i:s', filemtime($this->_cache_dir.$this->_cached_file)):'Cachemiss';
1138 } // END get_cache_update_time()
1141 * This Method returns the Type of Cache that was used ('normal' or 'fast')
1144 * @author Stefan Saasen <s@fase4.com>
1145 * @param string $rdf RDF File (Location)
1146 * @return string Displays RDF Content ( using _display() )
1147 * @see _remote_file, cache()
1149 function get_CacheType()
1151 return $this->_cache_type;
1155 * Returns true if cached file was used, otherwise false
1158 * @author Stefan Saasen <s@fase4.com>
1159 * @return array $options
1160 * @see _use_cached_file
1162 function is_cachedFile()
1164 return $this->_use_cached_file;
1168 * This Method deletes all the cached Files.
1170 * Please keep in mind to use this method just as a 'manual garbage collection'
1171 * You should cache the rss/rdf files locally to avoid unnecessary traffic.
1172 * (Both for your visitors and the Publisher)
1175 * @author Stefan Saasen <s@fase4.com>
1178 function clear_cache()
1180 $dir = dir($this->_cache_dir);
1181 while($file=$dir->read()) {
1182 // Exclude directories
1183 if (is_file($dir->path.$file) && substr($file, -6, 6) != '.cache' && substr($file, -4, 4) != '.log') {
1184 if(!@unlink($dir->path.$file)) {
1185 $this->_throw_exception("Unable to unlink ".$dir->path.$file."<br />\n<br />\nException at Line: ".__LINE__ );
1192 } // END clear_cache()
1195 * Cuts the String $string after $str_len and adds '... '
1198 * @param string $string String to be shortened
1199 * @param int $str_len length of the returned String (overall length including '... ')
1200 * @return string Cut String
1202 function _cut_string( $string, $str_len = '30' )
1204 if(strlen(trim($string))>$str_len) {
1205 $string = substr( trim($string) , 0, $str_len - 4);
1209 } // END _cut_string()
1212 * this Method implements simple Garbage Collection
1215 * @author Stefan Saasen <s@fase4.com>
1216 * @see _cache_dir, gc_probability, gc_maxlifetime
1218 function _garbage_collection()
1220 srand((double) microtime() * 1000000);
1221 if (mt_rand(1, 100) <= $this->gc_probability) {
1222 $dir = dir($this->_cache_dir);
1223 while($file=$dir->read()) {
1224 if (is_file($dir->path.$file) && substr($file, -6, 6) != '.cache' && substr($file, -4, 4) != '.log' && filemtime($dir->path.$file) <= time() - $this->_refresh ) {
1225 @unlink($dir->path.$file);
1232 /* ==== Proxy/Auth methods ==== */
1235 * this method sets a proxy server
1238 * @param string $phost Proxy Host
1239 * @param string $pport Prox Port
1240 * @author Marco Kraus <marco.kraus@siemens.com>
1242 function set_proxy($phost, $pport)
1244 $this->_use_proxy = true;
1247 $this->_phost = $phost;
1250 $this->_pport = $pport;
1254 * this method sets a proxy server authentification
1257 * @param string $pname Username
1258 * @param string $ppaswd Password
1259 * @author Marco Kraus <marco.kraus@siemens.com>
1261 function set_proxy_auth( $pname, $ppasswd )
1263 $this->_use_proxy_auth = true;
1266 $this->_pname = $pname;
1269 $this->_ppasswd = $ppasswd;
1274 * gets _remote_file into an array
1276 * needed, cause if you use a proxy, you have to open
1277 * a raw-tcp-socket to get the data
1280 * @author Marco Kraus <Marco.Kraus@siemens.com>
1282 * @see _use_proxy, cache()
1284 function _rdf_data()
1286 if ( $this->_use_proxy == true )
1288 // we need a raw socket here to connect to proxy
1289 $fp = fsockopen($this->_phost,$this->_pport);
1292 $this->_throw_exception( $this->_remote_file.' is not available with proxy' );
1294 if ( $this->_use_proxy_auth == true ) {
1295 fputs($fp, "GET ".$this->_remote_file." HTTP/1.0\r\nUser-Agent: Fase4 RDF-Reader/1.40 modified by Quix0r\r\n\r\n");
1297 fputs($fp, "GET ".$this->_remote_file." HTTP/1.0\r\nUser-Agent: Fase4 RDF-Reader/1.40 modified by Quix0r\r\nProxy-Authorization: Basic ".base64_encode("$this->_pname:$this->_ppasswd") ."\r\n\r\n");
1302 for ( $i = '0'; !feof ($fp) ; $i++)
1304 $usable_data[$i] = "";
1305 $usable_data[$i] = fgets($fp,4096);
1307 // PARSE HEADER ---- first line has to be <?xml, second rdf or rss, and third is blank
1309 // strstr did not fit (ask Rasmus why), so we compare each character
1310 if ( ($usable_data[$i][0] == '<' ) &&
1311 ($usable_data[$i][1] == '?' ) &&
1312 ($usable_data[$i][2] == 'x' ) &&
1313 ($usable_data[$i][3] == 'm' ) &&
1314 ($usable_data[$i][4] == 'l' ) ) {
1315 $usable_data[0] = $usable_data[$i]; // save current field
1316 $i = 1; // just reset array to start
1319 // there seems to be proxystuff after the <?xml....we delete this
1321 ($usable_data[$i][0] == '<' ) &&
1322 ($usable_data[$i][1] == 'r' ) &&
1323 ($usable_data[$i][2] == 'd' ) &&
1324 ($usable_data[$i][3] == 'f' ) &&
1325 ($usable_data[$i][4] == ':' )
1329 ($usable_data[$i][0] == '<' ) &&
1330 ($usable_data[$i][1] == 'r' ) &&
1331 ($usable_data[$i][2] == 's' ) &&
1332 ($usable_data[$i][3] == 's' )
1336 $usable_data[1] = $usable_data[$i]; // save current field
1337 $usable_data[2] = "\n";
1338 $i = 2; // just reset array to start
1343 return $usable_data;
1345 if (substr($this->_remote_file, 0, 7) != 'http://') {
1346 $this->_throw_exception( 'Cannot find http:// in '.$this->_remote_file.'!' );
1349 // Extract host information
1350 $host = substr($this->_remote_file, 7);
1351 // Extract the GET part
1353 if (strpos($host, '/') > 0) {
1354 $get = substr($host, strpos($host, '/'));
1355 $host = substr($host, 0, strpos($host, '/'));
1359 if (strpos($host, ':') > 0) {
1360 $port = substr($host, (strpos($host, ':') + 1));
1361 $host = substr($host, 0, (strpos($host, ':') - 1));
1364 // Start connection to server
1365 $fp = fsockopen($host, $port);
1367 $this->_throw_exception( $this->_remote_file.' is maybe not available.' );
1370 // Repare request line
1371 $request = sprintf("GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Fase4 RDF-Reader/1.40 modified by Quix0r\r\n\r\n", $get, $host);
1373 fputs($fp, $request);
1374 $reply = ''; $isContent = false; $dummy = '';
1377 while ( !feof($fp) ) {
1378 $read = trim(fgets($fp, 4096));
1379 if (substr($read, 0, 5) == '<?xml' || $isContent) {
1389 if ((count($dummy) > 0) && (count($reply) == 0) && (!$isContent)) {
1390 // Transfer content from dummy
1394 //die(htmlentities($reply));
1398 } // END _rdf_data()