* * Based loosely on RemoteRSS plugin. * I wrote this to parse a Blogrolling OPML feed. */ switch ($serendipity['lang']) { case 'de': @define('PLUGIN_REMOTEOPML_TITLE', 'Fremder OPML Feed'); @define('PLUGIN_REMOTEOPML_BLAHBLAH', 'Zeigt Einträge eines externen OPML-Feeds an'); @define('PLUGIN_REMOTEOPML_NUMBER', 'Anzahl der Einträge'); @define('PLUGIN_REMOTEOPML_NUMBER_BLAHBLAH', 'Wieviele Einträge sollen angezeigt werden? (Standard: alle im Feed)'); @define('PLUGIN_REMOTEOPML_SIDEBARTITLE', 'Feed-Titel'); @define('PLUGIN_REMOTEOPML_SIDEBARTITLE_BLAHBLAH', 'Titel der Feed-Anzeige in der Sidebar des Blogs'); @define('PLUGIN_REMOTEOPML_OPMLURI', 'OPML-URI'); @define('PLUGIN_REMOTEOPML_OPMLURI_BLAHBLAH', 'URI des OPML-Feeds, der angezeigt werden soll'); @define('PLUGIN_REMOTEOPML_OPMLTARGET', 'Link-Target'); @define('PLUGIN_REMOTEOPML_OPMLTARGET_BLAHBLAH', 'Target des Links zu einem der angezeigten OPML-Einträge (Standard: _blank)'); @define('PLUGIN_REMOTEOPML_NOURI', 'Kein OPML-Feed gewählt'); @define('PLUGIN_REMOTEOPML_CACHETIME', 'Wann wird der Feed aktualisiert?'); @define('PLUGIN_REMOTEOPML_CACHETIME_BLAHBLAH', 'Die Inhalte des fremden Feeds werden gecached. Sobald der Cache älter ist als X Minuten wird er aktualisiert (Standard: 3 Stunden)'); break; case 'en': case 'es': default: @define('PLUGIN_REMOTEOPML_TITLE', 'Remote OPML Feed'); @define('PLUGIN_REMOTEOPML_BLAHBLAH', 'Show items of a remote OPML feed'); @define('PLUGIN_REMOTEOPML_NUMBER', 'Number of entries'); @define('PLUGIN_REMOTEOPML_NUMBER_BLAHBLAH', 'How many entries should be displayed? (Default: every entry of the feed)'); @define('PLUGIN_REMOTEOPML_SIDEBARTITLE', 'Feed-Title'); @define('PLUGIN_REMOTEOPML_SIDEBARTITLE_BLAHBLAH', 'Title of the feed in the blog sidebar'); @define('PLUGIN_REMOTEOPML_OPMLURI', 'OPML URI'); @define('PLUGIN_REMOTEOPML_OPMLURI_BLAHBLAH', 'URI of the OPML feed which you want to display'); @define('PLUGIN_REMOTEOPML_NOURI', 'No OPML feed selected'); @define('PLUGIN_REMOTEOPML_OPMLTARGET', 'OPML target'); @define('PLUGIN_REMOTEOPML_OPMLTARGET_BLAHBLAH', 'Target of the link to one of the displayed OPML items (Default: _blank)'); @define('PLUGIN_REMOTEOPML_CACHETIME', 'When to update the feed?'); @define('PLUGIN_REMOTEOPML_CACHETIME_BLAHBLAH', 'The contents of a feed are stored in a cache which will be updated as soon as its older than X minutes (Default: 3 hours)'); break; } class XMLTree { function GetChildren($vals, &$i) { $children = array(); while (++$i < sizeof($vals)) { // compair type switch ($vals[$i]['type']) { case 'cdata': $children[] = $vals[$i]['value']; break; case 'complete': $children[] = array( 'tag' => $vals[$i]['tag'], 'attributes' => $vals[$i]['attributes'], 'value' => $vals[$i]['value'] ); break; case 'open': $children[] = array( 'tag' => $vals[$i]['tag'], 'attributes' => $vals[$i]['attributes'], 'value' => $vals[$i]['value'], 'children' => $this->GetChildren($vals, $i) ); break; case 'close': return $children; } } } function GetXMLTree($file) { $data = implode('', file($file)); // by: waldo@wh-e.com - trim space around tags not within $data = eregi_replace(">"."[[:space:]]+"."<","><",$data); // XML functions $p = xml_parser_create(); // by: anony@mous.com - meets XML 1.0 specification xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0); xml_parse_into_struct($p, $data, $vals, $index); xml_parser_free($p); $i = 0; $tree = array(); $tree[] = array( 'tag' => $vals[$i]['tag'], 'attributes' => $vals[$i]['attributes'], 'value' => $vals[$i]['value'], 'children' => $this->GetChildren($vals, $i) ); return $tree; } } define('OPMLDEBUG', '0'); class OPML { var $cacheOPMLHead; var $cacheOPMLBody; var $cacheOPMLOutline; function OPML() { $this->cacheOPMLHead = array(); $this->cacheOPMLBody = array(); $this->cacheOPMLOutline = array(); } function parseOPML($file) { $xmltree = new XMLTree(); $opmltree = $xmltree->GetXMLTree($file); return $opmltree[0]; } function findOPMLTag($arr, $tag) { $i = 0; $tagindex = false; $children = $arr['children']; while ($i < count($children)) { if ($children[$i]['tag'] == $tag) { $tagindex = $i; break; } ++$i; } return $tagindex !== false ? $tagindex : false; } function getOPMLTag($tree, $tag) { $tagindex = $this->findOPMLTag($tree, $tag); if (OPMLDEBUG == 1) { echo "\ngetOPMLTag('" . $tag . "') = " . $tagindex . "
\n";
            print_r($tree['children'][$tagindex]);
            echo "\n
\n"; } return $tagindex !== false ? $tree['children'][$tagindex] : false; } function getOPMLHead($tree) { $head = array(); if (isset($this->cacheOPMLHead) && count($this->cacheOPMLHead) != 0) $head = $this->cacheOPMLHead; else { if (OPMLDEBUG == 1) echo "\ngetOPMLHead
\n"; $head = $this->getOPMLTag($tree, 'head'); if ($head !== false) { $this->cacheOPMLHead = $head; if (OPMLDEBUG == 1) { echo "\nCaching head
\n";
                    print_r($this->cacheOPMLHead);
                    echo "\n
\n"; } } else if (OPMLDEBUG == 1) echo "\nfalse
\n"; } return $head['tag'] == 'head' ? $head : false; } function getOPMLBody($tree) { $body = array(); if (isset($this->cacheOPMLBody) && count($this->cacheOPMLBody) != 0) $body = $this->cacheOPMLBody; else { if (OPMLDEBUG == 1) echo "\ngetOPMLBody
\n"; $body = $this->getOPMLTag($tree, 'body'); if ($body !== false) { $this->cacheOPMLBody = $body; if (OPMLDEBUG == 1) { echo "\nCaching body
\n";
                    print_r($this->cacheOPMLBody);
                    echo "\n
\n"; } } else if (OPMLDEBUG == 1) echo "\nfalse
\n"; } return $body['tag'] == 'body' ? $body : false; } function getOPMLOutline($tree, $index) { if (isset($this->cacheOPMLOutline[$index])) return $this->cacheOPMLOutline[$index]; $body = $this->getOPMLBody($tree); if (!$body) { return false; } $outline = $body['children'][$index]; if ($outline['tag'] == 'outline') { $this->cacheOPMLOutline[$index] = $outline; if (OPMLDEBUG == 1) { echo "\ngetOPMLOutline[" . $index . "]
\n"; echo "\nCaching outline[" . $index . "]
\n";
                print_r($this->cacheOPMLOutline[$index]);
                echo "\n
\n"; } return $outline; } else return false; } function getOPMLOutlineAttr($tree, $index) { $outline = $this->getOPMLOutline($tree, $index); return $outline != false ? $outline['attributes'] : false; } } class serendipity_plugin_remoteopml extends serendipity_plugin { function introspect(&$propbag) { $propbag->add('name', PLUGIN_REMOTEOPML_TITLE); $propbag->add('description', PLUGIN_REMOTEOPML_BLAHBLAH); $propbag->add('configuration', array('number', 'dateformat', 'sidebartitle', 'opmluri', 'target', 'cachetime', 'markup')); } function introspect_config_item($name, &$propbag) { switch($name) { case 'number': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_REMOTEOPML_NUMBER); $propbag->add('description', PLUGIN_REMOTEOPML_NUMBER_BLAHBLAH); break; case 'dateformat': $propbag->add('type', 'string'); $propbag->add('name', GENERAL_PLUGIN_DATEFORMAT); $propbag->add('description', sprintf(GENERAL_PLUGIN_DATEFORMAT_BLAHBLAH, '%A, %B %e. %Y')); break; case 'sidebartitle': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_REMOTEOPML_SIDEBARTITLE); $propbag->add('description', PLUGIN_REMOTEOPML_SIDEBARTITLE_BLAHBLAH); break; case 'opmluri': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_REMOTEOPML_OPMLURI); $propbag->add('description', PLUGIN_REMOTEOPML_OPMLURI_BLAHBLAH); break; case 'target': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_REMOTEOPML_OPMLTARGET); $propbag->add('description', PLUGIN_REMOTEOPML_OPMLTARGET_BLAHBLAH); break; case 'cachetime': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_REMOTEOPML_CACHETIME); $propbag->add('description', PLUGIN_REMOTEOPML_CACHETIME_BLAHBLAH); break; case 'markup': $propbag->add('type', 'boolean'); $propbag->add('name', DO_MARKUP); $propbag->add('description', DO_MARKUP_DESCRIPTION); break; default: return false; } return true; } function generate_content(&$title) { global $serendipity; $number = $this->get_config('number'); $dateformat = $this->get_config('dateformat'); $sidebartitle = $this->get_config('sidebartitle'); $opmluri = $this->get_config('opmluri'); $target = $this->get_config('target'); $cachetime = $this->get_config('cachetime') * 60; $title = $sidebartitle; if (!$number || !is_numeric($number) || $number < 1) { $showAll = true; } else { $showAll = false; } if (!$dateformat || strlen($dateformat) < 1) { $dateformat = '%A, %B %e. %Y'; } if (!$target || strlen($target) < 1) { $target = '_blank'; } if (!$cachetime || !is_numeric($cachetime)) { $cachetime = 3 * 60 * 60; // 3 hours in seconds } if (trim($opmluri)) { $feedcache = $serendipity['serendipityPath'] . 'archives/remoteopml_cache_' . preg_replace('@[^a-z0-9]*@i', '', $opmluri) . '.dat'; if (!file_exists($feedcache) || filesize($feedcache) == 0 || filemtime($feedcache) < (time() - $cachetime)) { $opml = new OPML(); $opmltree = $opml->parseOPML($opmluri); if (OPMLDEBUG == 1) { echo "\n
\n";
                    print_r($opmltree);
                    echo "\n
\n"; } if ($opmltree['tag'] === 'opml') { $head = $opml->getOPMLHead($opmltree); $ownerName = $opml->getOPMLTag($head, 'ownerName'); $blogrolling = $ownerName != false ? ($ownerName['value'] == 'Blogroll Owner' ? true : false) : false; $i = 0; $content = ''; while (($showAll || ($i < $number)) && ($item = $opml->getOPMLOutlineAttr($opmltree, $i))) { if ($blogrolling === true) { $content .= '
  • ' . $item['text'] . ""; if (isset($item['isRecent'])) { $content .= ' *'; } $content .= "
    "; } else { if ($item['type'] == 'url') { $content .= '
  • ' . $item['text'] . ""; $content .= "
    "; } } ++$i; } /* Pretend to be a html_nugget so we can apply markup events. */ if ($this->get_config('markup', 'true') == 'true') { $entry = array('html_nugget' => $content); serendipity_plugin_api::hook_event('frontend_display', $entry); $content = $entry['html_nugget']; } $fp = @fopen($feedcache, 'w'); if ($fp) { fwrite($fp, $content); fclose($fp); } else { echo '
    '; } } else { echo ''; } } else { $content = file_get_contents($feedcache); } echo $content; } else { echo PLUGIN_REMOTEOPML_NOURI; } } } /* vim: set sts=4 ts=4 expandtab : */ ?>