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!
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
75 var $_decoding_mode = "utf8_decode";
78 * If $_link_target is set a target='xxx' attribute in each <a /> and <form /> html tag will be added
80 * Possible values are "_blank", "_content", "_parent", "_self", "_top"
85 var $_link_target = "_blank";
88 * vars for proxy settings - Prox Host
96 * vars for proxy settings - Prox Port
104 * vars for proxy settings - Prox Username
112 * vars for proxy settings - Prox Password
120 * just a flag for checking if proxy-support should be enabled
121 * set default to false (will be enabled if set_proxy is called)
127 var $_use_proxy = false;
130 * just a flag for checking if proxy-support with authentication
132 * set default to false (will be enabled if set_proxy is called)
138 var $_use_proxy_auth = false;
141 * The time the Files will be cached (in seconds).
146 var $_refresh = 60; // int
149 * The Name of the cached File.
154 var $_cached_file = ""; // String
157 * Indicates whether the cached or the remote file was used.
162 var $_use_cached_file = true;
165 * (fast|normal) depends on _use_dynamic_display(). _use_dynamic_display( TRUE ) -> 'normal', otherwise 'fast'
170 var $_cache_type = "fast";
173 * The Name of the Remote File.
178 var $_remote_file = "";
181 * Path to the Cache Directory.
186 var $_cache_dir = "cache/"; // String
189 * Indicates whether the Creating of the Cache Directory needs to be done or not.
194 var $_cache_dir_ok = false;
197 * Type of the file to be parsed (RSS or RDF).
199 * The Type depends on the root node
204 var $_type = "rss"; // string (rss or rdf)
207 * Array of Display Settings.
209 * Specific Parameters can be set to hidden. These are:
210 * image, channel and textinput. If set to "hidden" those elements won't be displayed.
215 var $_display_opt = array(
220 'cache_update' => "",
227 * Defines the width attribute in the table that holds the rdf/rss representation
231 * @see see_table_width()
233 var $_table_width = "100%";
236 * Indicates whether or not to use dynamic Display Settings
241 var $_use_dynamic_display = false;
249 var $_item_count = 0;
257 var $_max_count = false;
260 * Array containing the content of <channel />
265 var $_array_channel = array();
268 * Array containing the content of each <item />
273 var $_array_item = array();
276 * Array containing the content of <textinput />
281 var $_array_textinput = array();
284 * Array containing the content of <image />
289 var $_array_image = array();
292 * Array containing the Channel content. Just For internal XML Parser Purposes.
297 var $_citem = array();
300 * Array containing the Channel Parser Depth. Just For internal XML Parser Purposes.
305 var $_cdepth = array();
308 * Array containing the Channel tags. Just For internal XML Parser Purposes.
313 var $_ctags = array( "x" );
316 * Array containing the Channel content. Just For internal XML Parser Purposes.
321 var $_item = array(); // Array
324 * Array containing the Channel Parser Depth. Just For internal XML Parser Purposes.
329 var $_depth = array(); // Array
332 * Array containing the tags. Just For internal XML Parser Purposes.
337 var $_tags = array( "x" ); // Array
340 * Garbage collection: probability in percent
342 * @var integer 0 => never
345 var $gc_probability = 1;
358 var $_parse_mode = "";
367 * Constructor of our Class
369 * This Method checks if the Cache Directory can be found. Otherwise it tries to creat the Cache Directory at the specified Path.
370 * Additionally the Refresh Time is set to a default Value of 1200s (20 min).
373 * @author Stefan Saasen <s@fase4.com>
378 // default Value, to be overwritten in set_refresh()
379 $this->_refresh = (time() - 1200);
380 $this->_clear_cItems();
381 $this->_clear_Items();
385 * This Method starts the parsing of the specified RDF File. The File can be a local or a remote File.
388 * @author Stefan Saasen <s@fase4.com>
389 * @param string $rdf RDF File (Location)
390 * @return string Displays RDF Content ( using _display() )
391 * @see _remote_file, cache()
393 function parse_RDF( $rdf )
395 unset($this->_array_item);
396 $this->_remote_file = $rdf;
397 $this->out .= "<!-- http://www.fase4.com/rdf/ -->";
398 $this->out .= "<table width=\"".$this->_table_width."\">";
399 $this->out .= $this->cache();
400 $this->out .= "</table>";
402 $this->_item_count = 0;
407 * This Method is called when all parsing is finished to use the garbage collection
410 * @author Stefan Saasen <s@fase4.com>
411 * @param string $rdf RDF File (Location)
412 * @return string Displays RDF Content ( using _display() )
413 * @see _remote_file, cache()
415 function finish($return = false)
423 $this->_garbage_collection();
427 * With this method you can decide whether to use the normal cache and dynamic display Options or to use a static cache.
429 * 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.
430 * In this case you can not modify the display settings.
431 * processing time: ( 1.4792) --> remote file
432 * processing time: ( 0.0313) --> using 'normal cache' with display Modification turned on.
433 * processing time: ( 0.0019) --> using 'fast cache'
436 * @author Stefan Saasen <s@fase4.com>
437 * @param string $rdf RDF File (Location)
438 * @return string Displays RDF Content ( using _display() )
439 * @see _remote_file, cache()
441 function use_dynamic_display( $bool )
443 $this->_use_dynamic_display = $bool;
448 * This Method avtually parses the XML data.
451 * @author Stefan Saasen <s@fase4.com>
452 * @param string $data RDF File XML Data
453 * @see _clear_Items()
455 function _parse_xRDF( $data )
457 $this->_clear_Items();
458 $xml_parser = xml_parser_create();
459 xml_set_object($xml_parser,$this);
460 xml_parser_set_option($xml_parser,XML_OPTION_CASE_FOLDING,0);
461 xml_set_element_handler($xml_parser, "_startElement", "_endElement");
462 xml_set_character_data_handler($xml_parser, "_parseData");
463 if (!xml_parse($xml_parser, trim($data))) {
464 $this->_throw_exception(sprintf("XML error: %s at line %d",
465 xml_error_string(xml_get_error_code($xml_parser)),
466 xml_get_current_line_number($xml_parser))."<br /><br />Exception in function parse_RDF().");
468 xml_parser_free($xml_parser);
473 * This Methods allows you to set the Refresh Time
476 * @author Stefan Saasen <s@fase4.com>
477 * @param int $seconds time files will be cached (in seconds).
481 function set_refresh( $seconds )
483 $this->_refresh = (time() - $seconds);
487 function set_salt( $saltPara )
489 $this->salt = $saltPara;
494 * This Methods allows you to set the No. of <item>s to display
497 * @param int $int No of max <item>s
498 * @author Stefan Saasen <s@fase4.com>
500 * @see _max_count, _endElement()
502 function set_max_item( $int )
504 $this->_max_count = $int;
509 * This Methods allows you to set the Cache Directory
512 * @author Stefan Saasen <s@fase4.com>
513 * @param string $dir Path to Directory.
517 function set_CacheDir( $dir )
519 if(substr($dir, -1) != "/") {
522 $this->_cache_dir = $dir;
526 * This Method displays Error Messages and terminates the Execution of the Script
529 * @param string $msg Message to display on failure
530 * @author Stefan Saasen <s@fase4.com>
532 function _throw_exception( $msg )
534 $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>";
539 * This Method clears the Array containig the Items.
542 * @author Stefan Saasen <s@fase4.com>
545 function _clear_Items( ) {
546 $this->_item = array(
559 * This Method clears the Array containig the Channel Items.
562 * @author Stefan Saasen <s@fase4.com>
565 function _clear_cItems( ) {
566 $this->_citem = array(
573 'managingEditor'=>"",
593 * XML Parser Start Element Handler
596 * @author Stefan Saasen <s@fase4.com>
597 * @param mixed $parser a reference to the XML parser calling the handler.
598 * @param string $name contains the name of the element for which this handler is called.
599 * @param string $attrs contains an associative array with the element's attributes (if any).
600 * @see _get_ChannelData(), _clear_Items(), _type, _parse_mode, _depth, _tags, _cdepth, _ctags
602 function _startElement($parser, $name, $attrs) {
603 // We have to determine, which type of xml data we have to parse
605 $this->_type = "rss";
606 } elseif($name == "rdf:RDF" OR $name == "rdf") {
607 $this->_type = "rdf";
611 if ( $name == "channel" AND $this->_type != "rdf" ) {
612 $this->_parse_mode = "channel";
613 } elseif ( ($name=="item")
615 ||($name=="textinput")
616 ||(($name=="channel") && ($this->_type != "rss")) ) {
617 if($this->_parse_mode=="channel") {
618 $this->_get_ChannelData( $parser );
620 $this->_parse_mode = "all";
623 if( !isset( $this->_depth[$this->get_parser_id($parser)] ) ) {
624 $this->_depth[$this->get_parser_id($parser)] = 0;
626 $this->_depth[$this->get_parser_id($parser)]++;
627 array_push($this->_tags, $name);
629 if( !isset( $this->_cdepth[$this->get_parser_id($parser)] ) ) {
630 $this->_cdepth[$this->get_parser_id($parser)] = 0;
632 $this->_cdepth[$this->get_parser_id($parser)]++;
633 array_push($this->_ctags, $name);
634 } // END _startElement()
637 * Retrives the Channel Data in <rss> File
640 * @author Stefan Saasen <s@fase4.com>
641 * @param mixed $parser a reference to the XML parser calling the handler.
642 * @see _output, _display_opt, _citem
644 function _get_ChannelData( $parser )
646 $this->_citem["link"] = trim($this->_citem["link"]);
647 if (($this->_display_opt["sitelink"] == $this->_citem["link"]) && (!empty($this->_display_opt["reflink"])) && (!empty($this->_display_opt["refid"])))
649 $this->_citem["link"] .= $this->_display_opt["reflink"].$this->_display_opt["refid"];
652 if( empty($this->_display_opt["channel"]) OR
653 $this->_display_opt["channel"] != "hidden") {
654 $this->_output .= "<tr><td>\n";
655 $this->_output .= "<table border=\"0\" width=\"100%\" class=\"fase4_rdf_meta\" cellspacing=\"5\" cellpadding=\"2\">\n";
656 $this->_output .= "<tr><td class=\"fase4_rdf_main_title\"><div class=\"fase4_rdf_main_title\">".htmlspecialchars($this->_citem["title"])."</div></td></tr>\n";
657 $this->_output .= "<tr><td class=\"fase4_rdf\">".strip_tags($this->_citem["description"], "<a>, <img>")."</td></tr>\n";
658 $this->_output .= "<tr><td> </td></tr>\n";
659 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
660 if(isset($this->_display_opt["build"]) && $this->_display_opt["build"] != "hidden") {
661 if($this->_citem["lastBuildDate"]){$this->_output .= "build: ". $this->_citem["lastBuildDate"]."<br />";}
663 if(isset($this->_display_opt["cache_update"]) && $this->_display_opt["cache_update"] != "hidden" && ( $_update = $this->get_cache_update_time()) ) {
664 $this->_output .= "cache update: ".$_update."<br />\n";
666 $this->_output .= "<a href=\"".$this->_citem["link"]."\" ";
667 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
668 $this->_output .= ">".$this->_cut_string($this->_citem["link"])."</a>";
669 $this->_output .= "</td></tr>\n";
670 $this->_output .= "<tr><td><hr noshade width=\"100%\" size=\"1\"></td></tr>\n";
671 $this->_output .= "</table></td></tr>";
673 $this->_array_channel = array( "title"=>$this->_citem["title"],
674 "link"=>$this->_citem["link"],
675 "description"=>$this->_citem["description"],
676 "lastBuildDate"=>$this->_citem["lastBuildDate"]);
680 * XML Parser End Element Handler
683 * @author Stefan Saasen <s@fase4.com>
684 * @param mixed $parser a reference to the XML parser calling the handler.
685 * @param string $name contains the name of the element for which this handler is called.
686 * @see _clear_Items(), _type, _parse_mode, _depth, _tags, _cdepth, _ctags, _item, _output, _display_opt
688 function _endElement($parser, $name) {
689 array_pop($this->_tags);
690 $this->_depth[$this->get_parser_id($parser)]--;
691 array_pop($this->_ctags);
692 $this->_cdepth[$this->get_parser_id($parser)]--;
693 $this->_item["link"] = trim($this->_item["link"]);
694 if ((!empty($this->_display_opt["refid"])) && (!empty($this->_item["link"])))
696 if (!ereg("refid=", $this->_item["link"])) $this->_item["link"] .= "?refid=" . $this->_display_opt["refid"];
700 if(empty($this->_max_count) OR $this->_item_count < $this->_max_count) {
701 if($this->_item["title"] != $this->_item["description"]
702 AND $this->_item["description"]) {
704 // word-wrapping added by Roland Haeder <webmaster@mxchange.org>
705 if (($this->_word_wrap > 0) && (strlen($this->_item["description"]) > $this->_word_wrap))
707 // Switch off _use_nl2br
708 $this->_use_nl2br = false;
709 // First remove all \n
710 $this->_item["description"] = str_replace("\n", ' ', $this->_item["description"]);
711 // Wrap with <br />\n
712 $this->_item["description"] = wordwrap($this->_item["description"], $this->_word_wrap, "*<br>\n");
714 elseif (($this->_word_wrap == 0) && (!$this->_use_nl2br))
716 // Strip tags out instead when word-wrap is disabled
717 $this->_item["description"] = strip_tags($this->_item["description"], "<a>, <img>");
720 // nl2br added by Roland Haeder <webmaster@mxchange.org>
721 if ($this->_use_nl2br) $this->_item["description"] = nl2br($this->_item["description"]);
723 $this->_output .= "<tr><td class=\"fase4_rdf_title\"><div class=\"fase4_rdf_title\"><a class=\"fase4_rdf_title\" href=\"".$this->_item["link"]."\" ";
724 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
725 $this->_output .= ">".strip_tags($this->_item["title"], "<a>, <img>")."</a> (".$this->_item["pubDate"].")</div></td></tr>\n";
726 $this->_output .= "<tr><td class=\"fase4_rdf\">".$this->_item["description"]."</td></tr>\n";
727 // we just display the <hr> if there is a description
728 $this->_output .= "<tr><td><hr noshade=\"noshade\" size=\"1\" /></td></tr>\n";
730 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
731 $this->_output .= "<a href=\"".$this->_item["link"]."\" ";
732 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
733 $this->_output .= ">".$this->_item["title"]."</a></td></tr>\n";
735 $this->_array_item[] = array( "title"=>$this->_item["title"],
736 "link"=>$this->_item["link"],
737 "description"=>$this->_item["description"]);
738 ++$this->_item_count;
740 $this->_clear_Items();
743 if(isset($this->_display_opt["image"]) && ($this->_display_opt["image"] != "hidden") && $this->_item["url"]) {
744 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
745 $this->_output .= "<a href=\"".$this->_item["link"]."\" ";
746 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
747 $this->_output .= "><img src=\"".$this->_item["url"]."\"";
748 if(isset($this->_item["width"]) && isset($this->_item["height"])) {
749 $this->_output .= " width=\"".$this->_item["width"]."\" height=\"".$this->_item["height"]."\"";
751 $this->_output .= " alt=\"".$this->_item["title"]."\" border=\"0\" /></a></td></tr>\n";
753 $this->_array_image[] = array( "url"=>$this->_item["url"],
754 "link"=>$this->_item["link"],
755 "width"=>$this->_item["width"],
756 "height"=>$this->_item["height"]);
757 $this->_clear_Items();
758 } elseif( isset($this->_display_opt["image"] ) && ($this->_display_opt["image"] == "hidden") ) {
759 $this->_clear_Items();
764 if(isset($this->_display_opt["channel"]) AND $this->_display_opt["channel"] != "hidden" AND $this->_item["title"] != '') {
765 $this->_output .= "<tr><td>\n";
766 $this->_output .= '<table border="0" width="100%" class="fase4_rdf_meta" cellspacing="5" cellpadding="2">'."\n";
767 $this->_output .= "<tr><td class=\"fase4_rdf\"><div class=\"fase4_rdf_title\">".htmlspecialchars($this->_item["title"])."</div></td></tr>\n";
768 $this->_output .= "<tr><td class=\"fase4_rdf\">".strip_tags($this->_item["description"], "<a>, <img>")."</td></tr>\n";
769 $this->_output .= "<tr><td> </td></tr>\n";
770 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
771 if($this->_display_opt["build"] != "hidden") {
772 if($this->_item["lastBuildDate"]){$this->_output .= "build: ". $this->_item["lastBuildDate"]."<br />";}
774 if($this->_display_opt["cache_update"] != "hidden" && ( $_update = $this->get_cache_update_time()) ) {
775 $this->_output .= "cache update: ".$_update."<br />\n";
777 $this->_output .= "<a href=\"".$this->_item["link"]."\" ";
778 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
779 $this->_output .= ">".$this->_cut_string($this->_item["link"])."</a>\n";
780 $this->_output .= "</td></tr>\n";
781 $this->_output .= "</table></td></tr>\n";
783 $this->_array_channel = array( "title"=>$this->_item["title"],
784 "link"=>$this->_item["link"],
785 "description"=>$this->_item["description"],
786 "lastBuildDate"=>$this->_item["lastBuildDate"]);
787 $this->_clear_Items();
788 $this->_clear_cItems();
791 if(isset($this->_display_opt["textinput"]) && ($this->_display_opt["textinput"] != "hidden") && $this->_item["name"] && $this->_item["link"]) {
792 $this->_output .= "<tr><td class=\"fase4_rdf\">\n";
793 $this->_output .= "<form action=\"".$this->_item["link"]."\" ";
794 if(isset($this->_link_target)) { $this->_output .= "target=\"".$this->_link_target."\" "; }
795 $this->_output .= "method=\"get\">\n";
796 $this->_output .= "<div class=\"fase4_rdf_title\">".$this->_item["title"]."</div>";
797 $this->_output .= strip_tags($this->_item["description"], "<a>, <img>")."<br><br>\n";
798 $this->_output .= "<input class=\"fase4_rdf_input\" type=\"text\" name=\"".$this->_item["name"]."\"> \n";
799 $this->_output .= "<input class=\"fase4_rdf_input\" type=\"submit\" value=\"go\">";
800 $this->_output .= "</form>\n";
801 $this->_output .= "</td></tr>\n";
802 $this->_array_textinput = array( "title"=>$this->_item["title"],
803 "name"=>$this->_item["name"],
804 "link"=>$this->_item["link"],
805 "description"=>$this->_item["description"]);
806 $this->_clear_Items();
807 } elseif( isset($this->_display_opt["textinput"]) && ($this->_display_opt["textinput"] == "hidden") ) {
808 $this->_clear_Items();
816 * This Method returns the data from the <channel /> paragraph.
819 * @author Stefan Saasen <s@fase4.com>
821 * @see _array_channel
823 function get_array_channel( )
825 return $this->_array_channel;
829 * This Method returns the data from each <item /> paragraph.
832 * @author Stefan Saasen <s@fase4.com>
836 function get_array_item( )
838 return $this->_array_item;
842 * This Method returns the data from <textinput />.
845 * @author Stefan Saasen <s@fase4.com>
847 * @see _array_textinput
849 function get_array_textinput( )
851 return $this->_array_textinput;
855 * Getter for parser id from resource
858 * @author Roland Haeder <webmaster@mxchange.org>
861 function get_parser_id ($parser) {
866 if (is_resource($parser)) {
867 // Cast the resource into id
876 * This Method returns the data from <image />.
879 * @author Stefan Saasen <s@fase4.com>
883 function get_array_image( )
885 return $this->_array_image;
889 * XML Parser Data Handler
892 * @author Stefan Saasen <s@fase4.com>
893 * @param mixed $parser a reference to the XML parser calling the handler.
894 * @param string $text contains the character data as a string.
895 * @see _parse_mode, _item, _tags, _depth, _citem, _ctags, _cdepth
897 function _parseData($parser, $text)
899 // Deocing mode added by Roland Haeder <webmaster@mxchange.org>
900 switch ($this->_decoding_mode)
903 $text = utf8_decode($text);
907 $text = htmlentities($text);
911 $clean = preg_replace("/\s/", "", $text);
913 $text = preg_replace("/^\s+/", "", $text)."\n";
914 if($this->_parse_mode == "all") {
915 if ( isset($this->_item[$this->_tags[$this->_depth[$this->get_parser_id($parser)]]]) &&
916 $this->_item[$this->_tags[$this->_depth[$this->get_parser_id($parser)]]] ) {
917 $this->_item[$this->_tags[$this->_depth[$this->get_parser_id($parser)]]] .= $text;
919 $this->_item[$this->_tags[$this->_depth[$this->get_parser_id($parser)]]] = $text;
921 } elseif (isset($this->_parse_mode) && $this->_parse_mode == "channel") {
922 if ( isset($this->_citem[$this->_ctags[$this->_cdepth[$this->get_parser_id($parser)]]]) ) {
923 $this->_citem[$this->_ctags[$this->_cdepth[$this->get_parser_id($parser)]]] .= $text;
925 $this->_citem[$this->_ctags[$this->_cdepth[$this->get_parser_id($parser)]]] = $text;
932 * This Method allows you to choose if specific Parameters are displayed or not. These are:
933 * image, channel, textinput, build and cache_update. If set to "hidden" those elements won't be displayed.
936 * @author Stefan Saasen <s@fase4.com>
937 * @param array $options
940 function set_Options( $options = "" )
942 if(is_array( $options )) {
943 $this->_display_opt = $options;
946 unset($this->_display_opt);
952 * This Method allows you to define the width of the table that holds the representation of the rdf/rss file.
955 * @author Stefan Saasen <s@fase4.com>
956 * @param int $width attribute width in tag <table>
959 function set_table_width( $width = 400 )
961 $this->_table_width = $width;
966 * This Method returns an assocative Array with available Options.
968 * The Keys are the Name of the Options to be set.
969 * The Values are short Description of available Options.
972 * @author Stefan Saasen <s@fase4.com>
973 * @return array $options
976 function get_Options()
978 $options = array( "image"=>"If 'image' is set to \"hidden\" no image provided by the RDF Publisher will be displayed.",
979 "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",
980 "textinput"=>"If set to \"hidden\" no Input Form will be displayed",
981 "build"=>"If set to \"hidden\" the Build Date (if provided) of the RDF File will not be displayed",
982 "cache_update"=>"If set to \"hidden\" the Update Date/Time of the cached Rdf File will not be displayed");
987 * This Method returns the Content of the RDF File in one string. The String actually holds the whole XML Document.
990 * @author Stefan Saasen <s@fase4.com>
991 * @param string $rdf RDF File (Location)
992 * @return string XML Presentation of parsed RDF File
993 * @see _cached_file, _remote_file, _cache_dir, _refresh, _update_cache()
997 // checks if the cache directory already exists
998 // if not, the cache directory will be created
999 if(!$this->_cache_dir_ok) {
1000 $this->_create_cache_dir();
1002 if($this->_use_dynamic_display == true) {
1003 $this->_cached_file = md5("dynamic".$this->salt.$this->_remote_file) . '.cache';
1004 $this->_cache_type = "normal";
1006 $this->_cached_file = md5($this->salt.$this->_remote_file) . '.cache';
1007 $this->_cache_type = "fast";
1010 $_cache_f = $this->_cache_dir.$this->_cached_file;
1012 if ( (!file_exists($_cache_f)) || (filemtime($_cache_f) < $this->_refresh) || (filesize($_cache_f) == 0)) {
1013 // We have to parse the remote file
1014 $this->_use_cached_file = false;
1015 // --> we want to provide proper Information for Use in
1016 // get_cache_update_time()
1018 if($this->_use_dynamic_display == true) {
1019 $_rdf = @implode(" ", $this->_rdf_data()); // -> proxy
1021 $this->_throw_exception( $this->_remote_file." is not available" );
1023 $this->_parse_xRDF( $_rdf );
1024 $this->_update_cache( $_rdf );
1025 $data = $this->_output;
1027 $_rdf = @implode(" ", $this->_rdf_data()); // -> proxy
1029 $this->_throw_exception( $this->_remote_file." is not available" );
1031 $this->_parse_xRDF( $_rdf );
1032 $this->_update_cache( $this->_output );
1033 $data = $this->_output;
1036 // we can use the cached file
1037 $this->_use_cached_file = true;
1038 if($this->_use_dynamic_display == true) {
1039 $this->_parse_xRDF( implode(" ", file($_cache_f)) );
1040 $data = $this->_output;
1042 $data = @implode(" ", file($_cache_f));
1049 * This Methods creates the Cache Directory if the specified Directory does not exist.
1052 * @author Stefan Saasen <s@fase4.com>
1053 * @param string $dir Path to Directory.
1055 * @see _cache_dir, _cache_dir_ok
1057 function _create_cache_dir()
1060 if(!@is_dir($this->_cache_dir)) {
1061 $arr = explode("/", $this->_cache_dir);
1066 for($i = 0;$i<$c;$i++)
1069 $path .= $arr[$i]."/";
1070 if(!@is_dir($path)) {
1071 if(!@mkdir($path, 0777)) {
1072 $this->_throw_exception("failed to create directory:<b>".$this->_cache_dir."</b>.<br /><br />Exception on Line: ".__LINE__);
1078 $this->_cache_dir_ok = true;
1081 $this->_cache_dir_ok = true;
1084 } // END _create_cache_dir()
1087 * This Method updates the cached RDF Files and synchronises them with their remote Counterparts.
1090 * @author Stefan Saasen <s@fase4.com>
1091 * @param string $rdf RDF File (Location)
1092 * @see _cache_dir, _cached_file, _throw_exception()
1094 function _update_cache( $content = "" )
1096 $_local = @fopen( $this->_cache_dir.$this->_cached_file, 'w' );
1098 $this->_throw_exception( "Cannot open ".$this->_cached_file."<br /><br />Exception at Line: ".__LINE__ );
1101 if (fwrite( $_local, $content) === false) {
1102 $this->_throw_exception( "Cannot write to ".$this->_cached_file."<br /<br />Exeception at Line: ".__LINE__);
1106 @chmod( $this->_cache_dir.$this->_cached_file, 0666);
1108 } // END _update_cache()
1111 * This Method returns the Date/Time of last Cache Update of the actually parsed RDF File.
1114 * @author Stefan Saasen <s@fase4.com>
1115 * @return string Date/Time of last Update
1116 * @see _cache_dir, _cached_file
1118 function get_cache_update_time()
1120 return (file_exists($this->_cache_dir.$this->_cached_file))?date("d.m.Y H:i:s", filemtime($this->_cache_dir.$this->_cached_file)):"Cachemiss";
1121 } // END get_cache_update_time()
1124 * This Method returns the Type of Cache that was used ('normal' or 'fast')
1127 * @author Stefan Saasen <s@fase4.com>
1128 * @param string $rdf RDF File (Location)
1129 * @return string Displays RDF Content ( using _display() )
1130 * @see _remote_file, cache()
1132 function get_CacheType()
1134 return $this->_cache_type;
1138 * Returns true if cached file was used, otherwise false
1141 * @author Stefan Saasen <s@fase4.com>
1142 * @return array $options
1143 * @see _use_cached_file
1145 function is_cachedFile()
1147 return $this->_use_cached_file;
1151 * This Method deletes all the cached Files.
1153 * Please keep in mind to use this method just as a 'manual garbage collection'
1154 * You should cache the rss/rdf files locally to avoid unnecessary traffic.
1155 * (Both for your visitors and the Publisher)
1158 * @author Stefan Saasen <s@fase4.com>
1161 function clear_cache()
1163 $dir = dir($this->_cache_dir);
1164 while($file=$dir->read()) {
1165 // Exclude directories
1166 if (is_file($dir->path.$file) && substr($file, -6, 6) != ".cache" && substr($file, -4, 4) != ".log") {
1167 if(!@unlink($dir->path.$file)) {
1168 $this->_throw_exception("Unable to unlink ".$dir->path.$file."<br />\n<br />\nException at Line: ".__LINE__ );
1175 } // END clear_cache()
1178 * Cuts the String $string after $str_len and adds "... "
1181 * @param string $string String to be shortened
1182 * @param int $str_len length of the returned String (overall length including "... ")
1183 * @return string Cut String
1185 function _cut_string( $string, $str_len = "30" )
1187 if(strlen(trim($string))>$str_len) {
1188 $string = substr( trim($string) , 0, $str_len - 4);
1192 } // END _cut_string()
1195 * this Method implements simple Garbage Collection
1198 * @author Stefan Saasen <s@fase4.com>
1199 * @see _cache_dir, gc_probability, gc_maxlifetime
1201 function _garbage_collection()
1203 srand((double) microtime() * 1000000);
1204 if (mt_rand(1, 100) <= $this->gc_probability) {
1205 $dir = dir($this->_cache_dir);
1206 while($file=$dir->read()) {
1207 if (is_file($dir->path.$file) && substr($file, -6, 6) != ".cache" && substr($file, -4, 4) != ".log" && filemtime($dir->path.$file) <= time() - $this->_refresh ) {
1208 @unlink($dir->path.$file);
1215 /* ==== Proxy/Auth methods ==== */
1218 * this method sets a proxy server
1221 * @param string $phost Proxy Host
1222 * @param string $pport Prox Port
1223 * @author Marco Kraus <marco.kraus@siemens.com>
1225 function set_proxy($phost, $pport)
1227 $this->_use_proxy = true;
1230 $this->_phost = $phost;
1233 $this->_pport = $pport;
1237 * this method sets a proxy server authentification
1240 * @param string $pname Username
1241 * @param string $ppaswd Password
1242 * @author Marco Kraus <marco.kraus@siemens.com>
1244 function set_proxy_auth( $pname, $ppasswd )
1246 $this->_use_proxy_auth = true;
1249 $this->_pname = $pname;
1252 $this->_ppasswd = $ppasswd;
1257 * gets _remote_file into an array
1259 * needed, cause if you use a proxy, you have to open
1260 * a raw-tcp-socket to get the data
1263 * @author Marco Kraus <Marco.Kraus@siemens.com>
1265 * @see _use_proxy, cache()
1267 function _rdf_data()
1269 if ( $this->_use_proxy == true )
1271 // we need a raw socket here to connect to proxy
1272 $fp = fsockopen($this->_phost,$this->_pport);
1275 $this->_throw_exception( $this->_remote_file." is not available with proxy" );
1277 if ( $this->_use_proxy_auth == true ) {
1278 fputs($fp, "GET ".$this->_remote_file." HTTP/1.0\r\nUser-Agent: Fase4 RDF-Reader/1.40 modified by Quix0r\r\n\r\n");
1280 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");
1285 for ( $i = 0; !feof ($fp) ; $i++)
1287 $usable_data[$i] = "";
1288 $usable_data[$i] = fgets($fp,4096);
1290 // PARSE HEADER ---- first line has to be <?xml, second rdf or rss, and third is blank
1292 // strstr did not fit (ask Rasmus why), so we compare each character
1293 if ( ($usable_data[$i][0] == "<" ) &&
1294 ($usable_data[$i][1] == "?" ) &&
1295 ($usable_data[$i][2] == "x" ) &&
1296 ($usable_data[$i][3] == "m" ) &&
1297 ($usable_data[$i][4] == "l" ) ) {
1298 $usable_data[0] = $usable_data[$i]; // save current field
1299 $i = 1; // just reset array to start
1302 // there seems to be proxystuff after the <?xml....we delete this
1304 ($usable_data[$i][0] == "<" ) &&
1305 ($usable_data[$i][1] == "r" ) &&
1306 ($usable_data[$i][2] == "d" ) &&
1307 ($usable_data[$i][3] == "f" ) &&
1308 ($usable_data[$i][4] == ":" )
1312 ($usable_data[$i][0] == "<" ) &&
1313 ($usable_data[$i][1] == "r" ) &&
1314 ($usable_data[$i][2] == "s" ) &&
1315 ($usable_data[$i][3] == "s" )
1319 $usable_data[1] = $usable_data[$i]; // save current field
1320 $usable_data[2] = "\n";
1321 $i = 2; // just reset array to start
1326 return $usable_data;
1328 if (substr($this->_remote_file, 0, 7) != "http://") {
1329 $this->_throw_exception( "Cannot find http:// in ".$this->_remote_file."!" );
1332 // Extract host information
1333 $host = substr($this->_remote_file, 7);
1334 // Extract the GET part
1336 if (strpos($host, "/") > 0) {
1337 $get = substr($host, strpos($host, "/"));
1338 $host = substr($host, 0, strpos($host, "/"));
1342 if (strpos($host, ":") > 0) {
1343 $port = substr($host, (strpos($host, ":") + 1));
1344 $host = substr($host, 0, (strpos($host, ":") - 1));
1347 // Start connection to server
1348 $fp = fsockopen($host, $port);
1350 $this->_throw_exception( $this->_remote_file." is maybe not available." );
1353 // Repare request line
1354 $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);
1356 fputs($fp, $request);
1357 $reply = ""; $isContent = false; $dummy = "";
1360 while ( !feof($fp) ) {
1361 $read = trim(fgets($fp, 4096));
1362 if (substr($read, 0, 5) == "<?xml" || $isContent) {
1372 if ((count($dummy) > 0) && (count($reply) == 0) && (!$isContent)) {
1373 // Transfer content from dummy
1377 //die(htmlentities($reply));
1381 } // END _rdf_data()