OSDN Git Service

BugTrack/2176 showrss: Fix character encoding issues etc.
[pukiwiki/pukiwiki.git] / plugin / showrss.inc.php
index 5d24918..9968214 100644 (file)
 <?php
-/**
- *
- * showrss ¥×¥é¥°¥¤¥ó
- * 
- * ¥é¥¤¥»¥ó¥¹¤Ï PukiWiki ËÜÂΤÈƱ¤¸¤¯ GNU General Public License (GPL) ¤Ç¤¹¡£
- * http://www.gnu.org/licenses/gpl.txt
- *
- * pukiwikiÍѤΥץ饰¥¤¥ó¤Ç¤¹¡£
- * pukiwiki1.3.2°Ê¾å¤ÇÆ°¤¯¤È»×¤¤¤Þ¤¹¡£
- * 
- * º£¤Î¤È¤³¤íÆ°ºî¤µ¤»¤ë¤¿¤á¤Ë¤ÏPHP ¤Î xml extension ¤¬É¬¿Ü¤Ç¤¹¡£PHP¤ËÁȤ߹þ¤Þ¤ì¤Æ¤Ê¤¤¾ì¹ç¤Ï¤½¤Ã¤±¤Ê¤¤¥¨¥é¡¼¤¬½Ð¤ë¤È»×¤¤¤Þ¤¹¡£
- * Àµµ¬É½¸½ or Ê¸»úÎó´Ø¿ô¤Ç¤Ê¤ó¤È¤«¤Ê¤é¤Ê¤¯¤â¤Ê¤µ¤²¤Ê¤ó¤Ç¤¹¤¬¼ûÍפäƤɤ줯¤é¤¤¤¢¤ë¤Î¤«¤ï¤«¤é¤¤¤Î¤ÇÊÝα¤Ç¤¹¡£
- * mbstring ¤â¤¢¤ë¤Û¤¦¤¬¤¤¤¤¤Ç¤¹¡£
- * 
- * ¤Ê¤¤¾ì¹ç¤Ï¡¢ jcode.phps ¤ò¤Á¤ç¤³¤Ã¤È¤¤¤¸¤Ã¤Æ mb_convert_encoding ¤È¤¤¤¦´Ø¿ô¤òÀë¸À¤·¤Æ¤ª¤±¤Ð¤È¤ê¤¢¤¨¤º¤½¤ì¤Ã¤Ý¤¯ÊÑ´¹¤Ç¤­¤ë¤«¤â¤Ç¤¹¡£
- * http://www.spencernetwork.org/
- * 
- * ¤´Ï¢ÍíÀè:
- * do3ob wiki   ->   http://do3ob.com/
- * email        ->   hiro_do3ob@yahoo.co.jp
- * 
- * ÈòÆñ½ê       ->   http://do3ob.s20.xrea.com/
- *
- * version: $Id: showrss.inc.php,v 1.6 2003/03/02 06:53:50 panda Exp $
- * 
- */
-
-// RSSÃæ¤Î "&lt; &gt; &amp;" ¤Ê¤É¤ò °ìö "< > &" ¤ËÌ᤹¤«¡©      ¡ã "&amp;" ¤¬ "&amp;amp;" ¤Ë¤Ê¤Ã¤Á¤ã¤¦¤ÎÂкö
-if (!defined('SHOWRSS_VALUE_UNESCAPE')) {
-       define('SHOWRSS_VALUE_UNESCAPE', true);
-}
-
-// ¤½¤Î¸å¤â¤Ã¤«¤¤"< > &"¤Ê¤É¤ò"&lt; &gt; &amp;"¤Ë¤¹¤ë¤«¡©        ¡ã XSSÂкö¡©
-if (!defined('SHOWRSS_VALUE_ESCAPE')) {
-       define('SHOWRSS_VALUE_ESCAPE'  , true);
-}
-
-
-function plugin_showrss_init() {
-
-       global $_plugin_showrss_tmpl;
-
-       $_plugin_showrss_tmpl = array();
-       $_plugin_showrss_tmpl['default'] = array(
-               'main' => '<p>{list}</p>',
-               'list' => "<a href=\"{link}\" title=\"{description}\">{title}</a><br />\n",
-               'lastmodified' => "<p style=\"font-size:10px\"><strong>Last-Modified:{timestamp}</strong></p>\n"
-       );
-       $_plugin_showrss_tmpl['menubar'] = array(
-               'main' => "<ul class=\"recent_list\">\n{list}</ul>\n",
-               'list' => " <li><a href=\"{link}\" title=\"{title} ({description})\">{title}</a></li>\n",
-               'lastmodified' => "<p style=\"font-size:10px\"><strong>Last-Modified:{timestamp}</strong></p>\n"
-       );
-       $_plugin_showrss_tmpl['recent'] = array(
-               'main' => "<ul class=\"recent_list\">\n{list}</ul>\n",
-               'list' => " <li><a href=\"{link}\" title=\"{title} ({description})\">{title}</a></li>\n",
-               'lastmodified' => "<p style=\"font-size:10px\"><strong>Last-Modified:{timestamp}</strong></p>\n"
-       );
+// PukiWiki - Yet another WikiWikiWeb clone
+// showrss.inc.php
+// Copyright:
+//     2002-2017 PukiWiki Development Team
+//     2002      PANDA <panda@arino.jp>
+//     (Original)hiro_do3ob@yahoo.co.jp
+// License: GPL, same as PukiWiki
+//
+// Show RSS (of remote site) plugin
+// NOTE:
+//    * This plugin needs 'PHP xml extension'
+//    * Cache data will be stored as CACHE_DIR/*.tmp
+
+define('PLUGIN_SHOWRSS_USAGE', '#showrss(URI-to-RSS[,default|menubar|recent[,Cache-lifetime[,Show-timestamp]]])');
+
+// Show related extensions are found or not
+function plugin_showrss_action()
+{
+       if (PKWK_SAFE_MODE) die_message('PKWK_SAFE_MODE prohibit this');
+
+       $body = '';
+       foreach(array('xml', 'mbstring') as $extension){
+               $$extension = extension_loaded($extension) ?
+                       '&color(green){Found};' :
+                       '&color(red){Not found};';
+               $body .= '| ' . $extension . ' extension | ' . $$extension . ' |' . "\n";
+       }
+       return array('msg' => 'showrss_info', 'body' => convert_html($body));
 }
 
-function plugin_showrss_convert() {
-
-       global $_plugin_showrss_tmpl;
-
-       $local_tmpl = $_plugin_showrss_tmpl; // timestampÉÕ²ÃÍÑ
-
-       if (!extension_loaded('xml')) {
-               // xml ³ÈÄ¥µ¡Ç½¤¬Í­¸ú¤Ç¤Ê¤¤¾ì¹ç¡£
-               // http://www18.tok2.com/home/koumori27/xml/phpsax/phpsax_menu.html ¤ò»ÈÍѤ¹¤ë¤ÈƱ¤¸¤³¤È¤Ç¤­¤½¤¦¤À¤±¤É¥Ë¡¼¥º¤¢¤ë¤«¤Ê¡©
-               return plugin_showrss_private_error_message('xml extension is not loaded');
+function plugin_showrss_convert()
+{
+       static $_xml;
+
+       if (! isset($_xml)) $_xml = extension_loaded('xml');
+       if (! $_xml) return '#showrss: xml extension is not found<br />' . "\n";
+
+       $num = func_num_args();
+       if ($num == 0) return PLUGIN_SHOWRSS_USAGE . '<br />' . "\n";
+
+       $argv = func_get_args();
+       $timestamp = FALSE;
+       $cachehour = 0;
+       $template = $uri = '';
+       switch ($num) {
+       case 4: $timestamp = (trim($argv[3]) == '1');   /*FALLTHROUGH*/
+       case 3: $cachehour = trim($argv[2]);            /*FALLTHROUGH*/
+       case 2: $template  = strtolower(trim($argv[1]));/*FALLTHROUGH*/
+       case 1: $uri       = trim($argv[0]);
        }
 
-       if (func_num_args() == 0) {
-               // °ú¿ô¤¬¤Ê¤¤¾ì¹ç¤Ï¥¨¥é¡¼
-               return plugin_showrss_private_error_message('wrong parameter');
+       $class = ($template == '' || $template == 'default') ? 'ShowRSS_html' : 'ShowRSS_html_' . $template;
+       if (! is_numeric($cachehour))
+               return '#showrss: Cache-lifetime seems not numeric: ' . htmlsc($cachehour) . '<br />' . "\n";
+       if (! class_exists($class))
+               return '#showrss: Template not found: ' . htmlsc($template) . '<br />' . "\n";
+       if (! is_url($uri))
+               return '#showrss: Seems not URI: ' . htmlsc($uri) . '<br />' . "\n";
+
+       // Remove old caches in 5% rate
+       if (mt_rand(1, 20) === 1) {
+               plugin_showrss_cache_expire(24);
        }
-       
-       $array = func_get_args();
-       $rssurl = $tmplname = $usecache = $usetimestamp = '';
-       
-       switch (func_num_args()) {
-       case 4:
-               $usetimestamp = $array[3];
-       case 3:
-               $usecache = $array[2];
-       case 2:
-               $tmplname = $array[1];
-       case 1:
-               $rssurl = $array[0];
+       list($rss, $time) = plugin_showrss_get_rss($uri, $cachehour);
+       if ($rss === FALSE) return '#showrss: Failed fetching RSS from the server<br />' . "\n";
+       if (! is_array($rss)) {
+               // Show XML error message
+               return '#showrss: Error - ' . htmlsc($rss) . '<br />' . "\n";
        }
-
-       // ¶õÇò¤òÇÓ½ü
-       $rssurl       = trim($rssurl);
-       $tmplname     = trim($tmplname);
-       $usetimestamp = trim($usetimestamp);
-
-       if ($tmplname == '' or (is_array($local_tmpl[$tmplname]) === false)) {
-               $tmplname = 'default';
-       }
-
-       // RSS ¥Ñ¥¹¤ÎÃÍ¥Á¥§¥Ã¥¯
-       if (plugin_showrss_private_check_url($rssurl) == false) {
-               // url(¥í¡¼¥«¥ë¥Õ¥¡¥¤¥ë¥Ñ¥¹)¤¬ÉÔÀµ¤Ê¾ì¹ç
-               return plugin_showrss_private_error_message("syntax error '$rssurl'");
+       $time_display = '';
+       if ($timestamp > 0) {
+               $time_display = '<p style="font-size:10px; font-weight:bold">Last-Modified:' .
+                       get_date('Y/m/d H:i:s', $time) .  '</p>';
        }
 
-       if ($usecache > 0) {
-               if (file_exists(CACHE_DIR) === false) {
-                       // ¥­¥ã¥Ã¥·¥å¤ò»È¤ª¤¦¤È»×¤Ã¤¿¤±¤É¥­¥ã¥Ã¥·¥å¥Ç¥£¥ì¥¯¥È¥ê¤¬Â¸ºß¤·¤Ê¤¤¡£
-                       return plugin_showrss_private_error_message("don't exist:" . CACHE_DIR);
-               }
+       $obj = new $class($rss);
+       return $obj->toString($time_display);
+}
 
-               if (is_writable(CACHE_DIR) === false) {
-                       // ¥­¥ã¥Ã¥·¥å¥Ç¥£¥ì¥¯¥È¥ê¤Ï½ñ¤­¹þ¤ß²Äǽ¤«¡©
-                       return plugin_showrss_private_error_message("don't have permission to access :" . CACHE_DIR);
-               }
+// Create HTML from RSS array()
+class ShowRSS_html
+{
+       var $items = array();
+       var $class = '';
 
-               $expire = 60 * 60 * $usecache;
-               if (($filename = plugin_showrss_private_cache_rss($rssurl, $expire)) !== false && filesize($filename) !== 0) {
-                       // ¥­¥ã¥Ã¥·¥å¤ÇÂнè¤Ç¤­¤¿¾ì¹ç¤Ï url ¤ò¥­¥ã¥Ã¥·¥å¤Ë½ñ¤­´¹¤¨¤ë¡£
-                       $rssurl = $filename;
-               }
-               else {
-                       // ¥­¥ã¥Ã¥·¥å¤ÎÀ¸À®¤Ë¼ºÇÔ¤·¤¿¾ì¹ç¤Ï²¿¤â¤Ê¤«¤Ã¤¿¤Î¤´¤È¤¯¿¶Éñ¤¦¡¦¡¦¡¦ ¡ã¥¨¥é¡¼µ¯¤³¤¹¤Ù¤­¡©
-                       $usecache = 0;
+       function ShowRSS_html($rss)
+       {
+               $this->__construct($rss);
+       }
+       function __construct($rss)
+       {
+               foreach ($rss as $date=>$items) {
+                       foreach ($items as $item) {
+                               $link  = $item['LINK'];
+                               $title = $item['TITLE'];
+                               $passage = get_passage($item['_TIMESTAMP']);
+                               $link = '<a href="' . $link . '" title="' .  $title . ' ' .
+                                       $passage . '" rel="nofollow">' . $title . '</a>';
+                               $this->items[$date][] = $this->format_link($link);
+                       }
                }
        }
 
-       // ¥¿¥¤¥à¥¹¥¿¥ó¥×¤Ä¤±¤ë¤ó¤À¤±¤É¡£¤â¡¼¤Á¤ç¤¤¥¹¥Þ¡¼¥È¤Ë½ñ¤­¤¿¤¤¤Ê¡¢¡¢
-       $timestamp = '';
-       if ($usetimestamp > 0) {
-               if ($usecache > 0) {
-                       $timestamp = filemtime($rssurl);
-               }
-               else {
-                       $timestamp = time();
-               }
-               $timestamp = date('Y/m/d H:i:s', $timestamp);
-               $timestamp = str_replace('{timestamp}', $timestamp, $local_tmpl[$tmplname]['lastmodified']);
+       function format_link($link)
+       {
+               return $link . '<br />' . "\n";
        }
 
-       $parsed_rss_array = plugin_showrss_private_get_rss_array($rssurl);
+       function format_list($date, $str)
+       {
+               return $str;
+       }
 
-       if (is_string($parsed_rss_array)) {
-               // Ìá¤êÃͤ¬Ê¸»úÎó¤À¤È¥¨¥é¡¼¥á¥Ã¥»¡¼¥¸
-               return plugin_showrss_private_error_message($parsed_rss_array);
+       function format_body($str)
+       {
+               return $str;
        }
 
-       if (function_exists('mb_convert_encoding')) {
-               // ¥¨¥ó¥³¡¼¥É¤Ç¤­¤ë¾ì¹ç¤ÏSOURCE_ENCODING¤Ë¡£
-               foreach ($parsed_rss_array as $index => $parsed_rss) {
-                       foreach ($parsed_rss as $parsed_rss_key => $parsed_rss_value) {
-                               $parsed_rss_array[$index][$parsed_rss_key] = mb_convert_encoding($parsed_rss_value,SOURCE_ENCODING,'auto');
-                       }
-               }
+       function toString($timestamp)
+       {
+               $retval = '';
+               foreach ($this->items as $date=>$items)
+                       $retval .= $this->format_list($date, join('', $items));
+               $retval = $this->format_body($retval);
+               return <<<EOD
+<div{$this->class}>
+$retval$timestamp
+</div>
+EOD;
        }
-       return plugin_showrss_private_make_html($tmplname, $local_tmpl, $parsed_rss_array) . $timestamp;
 }
 
-// °Ê²¼¡¢showrss ¥×¥é¥¤¥Ù¡¼¥È¤Ê´Ø¿ô¤È¤«
+class ShowRSS_html_menubar extends ShowRSS_html
+{
+       var $class = ' class="small"';
 
-// ¥¨¥é¡¼¥á¥Ã¥»¡¼¥¸¡Ê´Ê°×¡Ë
-function plugin_showrss_private_error_message($msg) {
-       return '<strong>showrss:</strong>' . $msg;
-}
-
-// url¥Á¥§¥Ã¥¯
-// ¥í¡¼¥«¥ë¥Õ¥¡¥¤¥ë¤Î¾ì¹ç¤Ï showrss??????.tmp ¤ß¤¿¤¤¤Ê¥Õ¥¡¥¤¥ë̾¤¸¤ã¤Ê¤¤¤È¥¨¥é¡¼¤Ë¤Ê¤ê¤Þ¤¹¡£
-// ereg("showrss[a-z0-9_-]+\\.tmp") ¢«¤³¤ì¤Ë¥Þ¥Ã¥Á¤¹¤ì¤ÐOK!
-function plugin_showrss_private_check_url($rssurl) {
-       // parse_url¤ò¤«¤Þ¤·¤ÆÇÛÎó²½
-       $parsed = parse_url(strtolower(trim($rssurl)));
-
-       // scheme¤¬http,https,ftp¤Ê¤é̵¾ò·ï¤ÇOK
-       $scheme = array('http', 'https', 'ftp');
-       if (in_array($parsed['scheme'], $scheme)) {
-               return true;
-       }
-       elseif (isset($parsed['scheme']) == true) {
-               // ¤½¤ì°Ê³°¤Îscheme¤Ï¤È¤ê¤¢¤¨¤º¥¨¥é¡¼¤Ë¤·¤Æ¤ß¤ë¡£
-               return false;
+       function format_link($link) {
+               return '<li>' . $link . '</li>' . "\n";
        }
 
-       $filename = basename($parsed['path']);
-       if (ereg("showrss[a-z0-9_\\.-]+\\.tmp", $filename)) {
-               return true;
+       function format_body($str) {
+               return '<ul class="recent_list">' . "\n" . $str . '</ul>' . "\n";
        }
-
-       // ¤¹¤Ù¤Æ¤Î¾ò·ï¤Ë°ú¤Ã³Ý¤«¤é¤Ê¤¤¾ì¹ç¤Ï false
-       return false;
 }
-// ¥Æ¥ó¥×¥ì¡¼¥È¤ò¤Ä¤«¤Ã¤ÆrssÇÛÎ󤫤éhtml¤òºî¤ë
-function plugin_showrss_private_make_html($tmplname, $showrss_tmpl, $parsed_rss_array) {
 
-       // ¥Æ¥ó¥×¥ì¡¼¥ÈÆÃÍ­¤Î´Ø¿ô¤¬¤¢¤ë¾ì¹ç¡¢¤½¤¤¤Ä¤ò»È¤¦¡£
-       if (function_exists("plugin_showrss_private_make_html_" . $tmplname) === true) {
-               $makehtml = "plugin_showrss_private_make_html_" . $tmplname;
+class ShowRSS_html_recent extends ShowRSS_html
+{
+       var $class = ' class="small"';
+
+       function format_link($link) {
+               return '<li>' . $link . '</li>' . "\n";
        }
-       else {
-               $makehtml = "plugin_showrss_private_make_html_default";
+
+       function format_list($date, $str) {
+               return '<strong>' . $date . '</strong>' . "\n" .
+                       '<ul class="recent_list">' . "\n" . $str . '</ul>' . "\n";
        }
-       return $makehtml($tmplname, $showrss_tmpl, $parsed_rss_array);
 }
 
-// ¥Ç¥Õ¥©¥ë¥È¤Î¥Æ¥ó¥×¥ì¡¼¥ÈÃÖ¤­´¹¤¨´Ø¿ô
-function plugin_showrss_private_make_html_default($tmplname, $showrss_tmpl, $parsed_rss_array) {
-       $linklist = '';
-       // ÃÖ´¹¤¨
-       foreach ($parsed_rss_array as $index => $parsed_rss) {
-               $linkhtml = $showrss_tmpl[$tmplname]["list"];
-               foreach ($parsed_rss as $parsed_rss_key => $parsed_rss_value) {
-
-                       switch ($parsed_rss_key) {
-                       case "link":
-                               // ¥ê¥ó¥¯¤Î¾ì¹ç
-                               // XSS Âкö¤Ç "  > ¤È¤«ÊÑ´¹¡©
-                               break;
-                       case "description":
-                               if ($unixtime = strtotime(trim($parsed_rss_value))) {
-                                       $parsed_rss_value = plugin_showrss_private_make_update_label($unixtime);
-                               }
-                               break;
-                       default:
-                               // ¤Ê¤·
-                       }
-                       $parsed_rss_value = plugin_showrss_private_escape($parsed_rss_value);
-
-                       $linkhtml = str_replace("{" . $parsed_rss_key . "}", trim($parsed_rss_value), $linkhtml);
+// Get and save RSS
+function plugin_showrss_get_rss($target, $cachehour)
+{
+       $buf  = '';
+       $time = NULL;
+       if ($cachehour) {
+               $filename = CACHE_DIR . encode($target) . '.tmp';
+               // Remove expired cache
+               plugin_showrss_cache_expire_file($filename, $cachehour);
+               // Get the cache not expired
+               if (is_readable($filename)) {
+                       $buf  = join('', file($filename));
+                       $time = filemtime($filename) - LOCALZONE;
                }
-               $linklist .= $linkhtml;
        }
-       $linklist = str_replace("{list}", $linklist, $showrss_tmpl[$tmplname]["main"]);
-       return $linklist;
-}
 
-// recentÉ÷¤ËÃÖ¤­´¹¤¨¤ë´Ø¿ô
-function plugin_showrss_private_make_html_recent($tmplname, $showrss_tmpl, $parsed_rss_array) {
-
-       $last = $linklist = $temp = '';
-       // ÃÖ´¹¤¨
-       foreach ($parsed_rss_array as $index => $parsed_rss) {
-
-               if (strtotime($parsed_rss['description']) !== false ) {
-                       if (date('Y-m-d', strtotime($parsed_rss['description'])) !== $last) {
-                               if ($temp != '') {
-                                       $linklist .= "<p><strong>$last</strong></p>";
-                                       $linklist .= str_replace('{list}', $temp, $showrss_tmpl[$tmplname]['main']);
-                                       $temp = '';
-                               }
-                               $last = date('Y-m-d', strtotime($parsed_rss['description']));
-                       }
+       if (is_null($time)) {
+               // Newly get RSS
+               $data = pkwk_http_request($target);
+               if ($data['rc'] !== 200) {
+                       return array(FALSE, 0);
                }
-
-               $linkhtml = $showrss_tmpl[$tmplname]["list"];
-               foreach ($parsed_rss as $parsed_rss_key => $parsed_rss_value) {
-
-                       switch ($parsed_rss_key) {
-                       case "link":
-                               // ¥ê¥ó¥¯¤Î¾ì¹ç
-                               // XSS Âкö¤Ç "  > ¤È¤«ÊÑ´¹¡©
-                               break;
-                       case "description":
-                               if ($unixtime = strtotime(trim($parsed_rss_value))) {
-                                       $parsed_rss_value = plugin_showrss_private_make_update_label($unixtime);
-                               }
-                               break;
-                       default:
-                               // ¤Ê¤·
-                       }
-                       $parsed_rss_value = plugin_showrss_private_escape($parsed_rss_value);
-
-                       $linkhtml = str_replace("{" . $parsed_rss_key . "}", trim($parsed_rss_value), $linkhtml);
+               $buf = $data['data'];
+               $time = UTIME;
+
+               // Save RSS into cache
+               if ($cachehour) {
+                       $fp = fopen($filename, 'w');
+                       fwrite($fp, $buf);
+                       fclose($fp);
                }
-               $temp .= $linkhtml;
        }
-       if ($last != '')
-               $linklist .= "<p><strong>$last</strong></p>";
-       if ($temp != '')
-               $linklist .= str_replace("{list}", $temp, $showrss_tmpl[$tmplname]["main"]);
-       return $linklist;
+       // Parse
+       $obj = new ShowRSS_XML();
+       $obj->modified_date = (is_null($time) ? UTIME : $time);
+       return array($obj->parse($buf),$time);
 }
 
-// xssÂкö¤Ã¤Ý¤¤¤è¤¦¤Ê
-function plugin_showrss_private_escape($target) {
-
-       if (SHOWRSS_VALUE_UNESCAPE) {
-               $target = strtr($target, array_flip(get_html_translation_table(ENT_COMPAT)));
+// Remove cache if expired limit exeed
+function plugin_showrss_cache_expire($cachehour)
+{
+       $expire = $cachehour * 60 * 60; // Hour
+       $dh = dir(CACHE_DIR);
+       while (($file = $dh->read()) !== FALSE) {
+               if (substr($file, -4) != '.tmp') continue;
+               $file = CACHE_DIR . $file;
+               $last = time() - filemtime($file);
+               if ($last > $expire) unlink($file);
        }
-
-       if (SHOWRSS_VALUE_ESCAPE) {
-               $target = htmlspecialchars($target);
-       }
-       return $target;
-}
-
-// rss¤ò¼èÆÀ¡¦ÇÛÎó²½
-function plugin_showrss_private_get_rss_array($rss) {
-       global $_plugin_showrss_insideitem,$_plugin_showrss_tag,$_plugin_showrss_title,
-       $_plugin_showrss_description,$_plugin_showrss_link,$_plugin_showrss_parsed;
-
-       // ½é´ü²½
-       $_plugin_showrss_insideitem = false;
-       $_plugin_showrss_tag = $_plugin_showrss_title = $_plugin_showrss_description = $_plugin_showrss_link = "";
-       $_plugin_showrss_parsed = array();
-
-       $xml_parser = xml_parser_create();
-       xml_set_element_handler($xml_parser, "plugin_showrss_private_start_element", "plugin_showrss_private_end_element");
-       xml_set_character_data_handler($xml_parser, "plugin_showrss_private_character_data");
-       if (!($fp = @fopen($rss,"r"))) return("can't open $rss");
-       while ($data = fread($fp, 4096))
-               if (!xml_parse($xml_parser, $data, feof($fp))) {
-                       return(sprintf("XML error: %s at line %d in %s",
-                                      xml_error_string(xml_get_error_code($xml_parser)),
-                                      xml_get_current_line_number($xml_parser), $rss));
-               }
-       fclose($fp);
-       xml_parser_free($xml_parser);
-       return $_plugin_showrss_parsed;
-}
-
-
-// ¹¹¿·»þ´Ö¤òpukiwikiÉ÷¤ËÊÑ´¹¡©
-function plugin_showrss_private_make_update_label($time, $utime = UTIME) {
-       $time = $utime - $time;
-
-       if (ceil($time / 60) < 60)
-               $result = ceil($time / 60)."m";
-       else if (ceil($time / 60 / 60) < 24)
-               $result = ceil($time / 60 / 60)."h";
-       else
-               $result = ceil($time / 60 / 60 / 24)."d";
-
-       return $result;
+       $dh->close();
 }
 
-// xml parser¤Î¥Ï¥ó¥É¥é´Ø¿ô
-function plugin_showrss_private_start_element($parser, $name, $attrs) {
-       global $_plugin_showrss_insideitem, $_plugin_showrss_tag, $_plugin_showrss_title, $_plugin_showrss_description, $_plugin_showrss_link;
-       if ($_plugin_showrss_insideitem) {
-               $_plugin_showrss_tag = $name;
-       }
-       else if ($name == "ITEM") {
-               $_plugin_showrss_insideitem = true;
-       }
-}
-// xml parser¤Î¥Ï¥ó¥É¥é´Ø¿ô
-function plugin_showrss_private_end_element($parser, $name) {
-       global $_plugin_showrss_insideitem, $_plugin_showrss_tag, $_plugin_showrss_title, $_plugin_showrss_description, $_plugin_showrss_link, $_plugin_showrss_parsed;
-       if ($name == "ITEM") {
-
-               $_plugin_showrss_parsed[] = array(
-                       "link"  =>  $_plugin_showrss_link,
-                       "title" =>  $_plugin_showrss_title,
-                       "description" => $_plugin_showrss_description
-                       );
-
-
-               $_plugin_showrss_title = "";
-               $_plugin_showrss_description = "";
-               $_plugin_showrss_link = "";
-               $_plugin_showrss_insideitem = false;
+/**
+ * Remove single file cache if expired limit exeed
+ * @param $filename
+ * @param $cachehour
+ */
+function plugin_showrss_cache_expire_file($filename, $cachehour)
+{
+       $expire = $cachehour * 60 * 60; // Hour
+       $last = time() - filemtime($filename);
+       if ($last > $expire) {
+               unlink($filename);
        }
 }
 
-// xml parser ¤Î¥Ï¥ó¥É¥é´Ø¿ô
-function plugin_showrss_private_character_data($parser, $data) {
-       global $_plugin_showrss_insideitem, $_plugin_showrss_tag, $_plugin_showrss_title, $_plugin_showrss_description, $_plugin_showrss_link;
-       if ($_plugin_showrss_insideitem) {
-               switch ($_plugin_showrss_tag) {
-               case "TITLE":
-                       $_plugin_showrss_title .= $data;
-                       break;
-               case "DESCRIPTION":
-                       $_plugin_showrss_description .= $data;
-                       break;
-               case "LINK":
-                       $_plugin_showrss_link .= $data;
-                       break;
+// Get RSS and array() them
+class ShowRSS_XML
+{
+       var $items;
+       var $item;
+       var $is_item;
+       var $tag;
+       var $encoding;
+       var $modified_date;
+
+       function parse($buf)
+       {
+               $this->items   = array();
+               $this->item    = array();
+               $this->is_item = FALSE;
+               $this->tag     = '';
+               $utf8 = 'UTF-8';
+               $this->encoding = $utf8;
+               // Detect encoding
+               $matches = array();
+               if(preg_match('/<\?xml [^>]*\bencoding="([a-z0-9-_]+)"/i', $buf, $matches)) {
+                       $encoding = $matches[1];
+                       if (strtoupper($encoding) !== $utf8) {
+                               // xml_parse() fails on non UTF-8 encoding attr in XML decLaration
+                               $buf = preg_replace('/<\?xml ([^>]*)\bencoding="[a-z0-9-_]+"/i', '<?xml $1', $buf);
+                               // xml_parse() requires UTF-8 compatible encoding
+                               $buf = mb_convert_encoding($buf, $utf8, $encoding);
+                       }
                }
+               // Parsing
+               $xml_parser = xml_parser_create($utf8);
+               xml_set_element_handler($xml_parser, array(& $this, 'start_element'), array(& $this, 'end_element'));
+               xml_set_character_data_handler($xml_parser, array(& $this, 'character_data'));
+               if (! xml_parse($xml_parser, $buf, 1)) {
+                       return sprintf('XML error: %s at line %d in %s',
+                               xml_error_string(xml_get_error_code($xml_parser)),
+                               xml_get_current_line_number($xml_parser),
+                               (strlen($buf) < 500 ? $buf : substr($buf, 0, 500) . '...'));
+               }
+               xml_parser_free($xml_parser);
+               return $this->items;
        }
-}
-
-// -- ¥­¥ã¥Ã¥·¥å¼þ¤ê -- //
 
-// ¥­¥ã¥Ã¥·¥å¤ò¥³¥ó¥È¥í¡¼¥ë
-function plugin_showrss_private_cache_rss($target, $expire) {
-       // ´ü¸ÂÀÚ¤ì¤Î¥­¥ã¥Ã¥·¥å¤ò¥¯¥ê¥¢
-       plugin_showrss_private_cache_garbage_collection(CACHE_DIR, $expire);
-       // ¥­¥ã¥Ã¥·¥å¤¬¤¢¤ì¤Ð¼èÆÀ¤¹¤ë
-       if (($result = plugin_showrss_private_cache_fetch($target, CACHE_DIR, $expire)) !== false) {
-               return $result;
+       function escape($str)
+       {
+               // Unescape already-escaped chars (&lt;, &gt;, &amp;, ...) in RSS body before htmlsc()
+               $str = strtr($str, array_flip(get_html_translation_table(ENT_COMPAT)));
+               // Escape
+               $str = htmlsc($str);
+               // Encoding conversion
+               $str = mb_convert_encoding($str, SOURCE_ENCODING, $this->encoding);
+               return trim($str);
        }
 
-       $data = implode('', file($target));
-
-       if (($filename = plugin_showrss_private_cache_save($data, $target, CACHE_DIR)) === false) {
-               return false;
+       // Tag start
+       function start_element($parser, $name, $attrs)
+       {
+               if ($this->is_item) {
+                       $this->tag     = $name;
+               } else if ($name == 'ITEM') {
+                       $this->is_item = TRUE;
+               }
        }
 
-       return $filename;
-
-}
-
-// ¥­¥ã¥Ã¥·¥å¤¬¤¢¤ë¤«Ä´¤Ù¤ë¡£Â¸ºß¤¹¤ë¾ì¹ç¥Õ¥¡¥¤¥ë̾
-function plugin_showrss_private_cache_fetch($target, $dir) {
-
-       $filename = $dir . encode($target) . ".tmp";
+       // Tag end
+       function end_element($parser, $name)
+       {
+               if (! $this->is_item || $name != 'ITEM') return;
+
+               $item = array_map(array(& $this, 'escape'), $this->item);
+               $this->item = array();
+
+               if (isset($item['DC:DATE'])) {
+                       $time = plugin_showrss_get_timestamp($item['DC:DATE'], $this->modified_date);
+                       
+               } else if (isset($item['PUBDATE'])) {
+                       $time = plugin_showrss_get_timestamp($item['PUBDATE'], $this->modified_date);
+               } else {
+                       $time_from_desc = FALSE;
+                       if (isset($item['DESCRIPTION']) &&
+                               (($description = trim($item['DESCRIPTION'])) != '')) {
+                               $time_from_desc = strtotime($description);
+                       }
+                       if ($time_from_desc !== FALSE && $time_from_desc !== -1) {
+                               $time = $time_from_desc - LOCALZONE;
+                       } else {
+                               $time = time() - LOCALZONE;
+                       }
+               }
+               $item['_TIMESTAMP'] = $time;
+               $date = get_date('Y-m-d', $item['_TIMESTAMP']);
 
-       if (!is_readable($filename)) {
-               return false;
+               $this->items[$date][] = $item;
+               $this->is_item        = FALSE;
        }
 
-       return $filename;
-}
-
-// ¥­¥ã¥Ã¥·¥å¤òÊݸ
-function plugin_showrss_private_cache_save($data, $target, $dir) {
-       $filename = $dir . encode($target) . ".tmp";
-       // lock¤¤¤é¤Ê¤¤¤«¤Ê¡©
-       $fp = fopen($filename, "w");
-       fwrite($fp, $data);
-       fclose($fp);
-       return $filename;
-}
-
-// ´ü¸ÂÀÚ¤ì¤Î¥Õ¥¡¥¤¥ë¤òºï½ü
-function plugin_showrss_private_cache_garbage_collection($dir, $expire) {
-
-       $dh = dir($dir);
-       while (($filename = $dh->read()) !== false)
+       function character_data($parser, $data)
        {
-               if (substr($filename,-4) != '.tmp')
-               {
-                       continue;
-               }
-
-               $last = time() - filemtime($dir . $filename);
+               if (! $this->is_item) return;
+               if (! isset($this->item[$this->tag])) $this->item[$this->tag] = '';
+               $this->item[$this->tag] .= $data;
+       }
+}
 
-               if ($last > $expire)
-               {
-                       unlink($dir . $filename);
+function plugin_showrss_get_timestamp($str, $default_date)
+{
+       $str = trim($str);
+       if ($str == '') return UTIME;
+
+       $matches = array();
+       if (preg_match('/(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})(([+-])(\d{2}):(\d{2}))?/', $str, $matches)) {
+               $time = strtotime($matches[1] . ' ' . $matches[2]);
+               if ($time === FALSE || $time === -1) {
+                       $time = $default_date;
+               } else if (isset($matches[3])) {
+                       $diff = ($matches[5] * 60 + $matches[6]) * 60;
+                       $time += ($matches[4] == '-' ? $diff : -$diff);
                }
+               return $time;
+       } else {
+               $time = strtotime($str);
+               return ($time === FALSE || $time === -1) ? $default_date : $time - LOCALZONE;
        }
-
-       $dh->close();
-
 }
-
-?>
\ No newline at end of file