[ Index ] |
|
Code source de Serendipity 1.2 |
1 <?php # $Id: serendipity_plugin_remoterss.php 1749 2007-07-05 11:10:51Z garvinhicking $ 2 3 // Contributed by Udo Gerhards <udo@babyblaue-seiten.de> 4 // OPML Contributed by Richard Thomas Harrison <rich@mibnet.plus.com> 5 6 // Probe for a language include with constants. Still include defines later on, if some constants were missing 7 $probelang = dirname(__FILE__) . '/' . $serendipity['charset'] . 'lang_' . $serendipity['lang'] . '.inc.php'; 8 if (file_exists($probelang)) { 9 include $probelang; 10 } 11 12 include dirname(__FILE__) . '/lang_en.inc.php'; 13 14 class s9y_remoterss_XMLTree { 15 function GetChildren($vals, &$i) { 16 $children = array(); 17 $cnt = sizeof($vals); 18 while (++$i < $cnt) { 19 // compare type 20 switch ($vals[$i]['type']) { 21 case 'cdata': 22 $children[] = $vals[$i]['value']; 23 break; 24 25 case 'complete': 26 $children[] = array( 27 'tag' => $vals[$i]['tag'], 28 'attributes' => $vals[$i]['attributes'], 29 'value' => $vals[$i]['value'] 30 ); 31 break; 32 33 case 'open': 34 $children[] = array( 35 'tag' => $vals[$i]['tag'], 36 'attributes' => $vals[$i]['attributes'], 37 'value' => $vals[$i]['value'], 38 'children' => $this->GetChildren($vals, $i) 39 ); 40 break; 41 42 case 'close': 43 return $children; 44 } 45 } 46 } 47 48 function GetXMLTree($file) { 49 require_once S9Y_PEAR_PATH . 'HTTP/Request.php'; 50 serendipity_request_start(); 51 $req = &new HTTP_Request($file); 52 53 if (PEAR::isError($req->sendRequest()) || $req->getResponseCode() != '200') { 54 $data = file_get_contents($file); 55 } else { 56 // Fetch file 57 $data = $req->getResponseBody(); 58 } 59 serendipity_request_end(); 60 61 // Global replacements 62 // by: waldo@wh-e.com - trim space around tags not within 63 $data = eregi_replace('>[[:space:]]+<', '><', $data); 64 65 // Flatten the input opml file to not have nested categories 66 $data = preg_replace('@<outline[^>]+[^/]>@imsU', '', $data); 67 $data = str_replace('</outline>', '', $data); 68 69 // XML functions 70 $xml_string = '<?xml version="1.0" encoding="UTF-8" ?>'; 71 if (preg_match('@(<\?xml.+\?>)@imsU', $data, $xml_head)) { 72 $xml_string = $xml_head[1]; 73 } 74 75 $encoding = 'UTF-8'; 76 if (preg_match('@encoding="([^"]+)"@', $xml_string, $xml_encoding)) { 77 $encoding = $xml_encoding[1]; 78 } 79 80 $p = xml_parser_create($encoding); 81 // by: anony@mous.com - meets XML 1.0 specification 82 @xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0); 83 xml_parser_set_option($p, XML_OPTION_TARGET_ENCODING, LANG_CHARSET); 84 xml_parse_into_struct($p, $data, $vals, $index); 85 xml_parser_free($p); 86 87 $i = 0; 88 $tree = array(); 89 $tree[] = array( 90 'tag' => $vals[$i]['tag'], 91 'attributes' => $vals[$i]['attributes'], 92 'value' => $vals[$i]['value'], 93 'children' => $this->GetChildren($vals, $i) 94 ); 95 96 return $tree; 97 } 98 } 99 100 define('OPMLDEBUG', '0'); 101 102 class s9y_remoterss_OPML { 103 var $cacheOPMLHead; 104 var $cacheOPMLBody; 105 var $cacheOPMLOutline; 106 107 function s9y_remoterss_OPML() { 108 $this->cacheOPMLHead = array(); 109 $this->cacheOPMLBody = array(); 110 $this->cacheOPMLOutline = array(); 111 } 112 113 function parseOPML($file) { 114 $xmltree = new s9y_remoterss_XMLTree(); 115 $opmltree = $xmltree->GetXMLTree($file); 116 117 return $opmltree[0]; 118 } 119 120 function findOPMLTag($arr, $tag) { 121 $i = 0; 122 $tagindex = false; 123 $children = $arr['children']; 124 $cnt = count($children); 125 126 while ($i < $cnt) { 127 128 if ($children[$i]['tag'] == $tag) { 129 $tagindex = $i; 130 break; 131 } 132 133 ++$i; 134 } 135 136 return $tagindex !== false ? $tagindex : false; 137 } 138 139 function getOPMLTag($tree, $tag) { 140 $tagindex = $this->findOPMLTag($tree, $tag); 141 142 if (OPMLDEBUG == 1) { 143 echo "\ngetOPMLTag('" . $tag . "') = " . $tagindex . "<pre>\n"; 144 print_r($tree['children'][$tagindex]); 145 echo "\n</pre>\n"; 146 } 147 148 return $tagindex !== false ? $tree['children'][$tagindex] : false; 149 } 150 151 function getOPMLHead($tree) { 152 $head = array(); 153 154 if (isset($this->cacheOPMLHead) && count($this->cacheOPMLHead) != 0) { 155 $head = $this->cacheOPMLHead; 156 } else { 157 158 if (OPMLDEBUG == 1) { 159 echo "\ngetOPMLHead<br />\n"; 160 } 161 162 $head = $this->getOPMLTag($tree, 'head'); 163 164 if ($head !== false) { 165 $this->cacheOPMLHead = $head; 166 167 if (OPMLDEBUG == 1) { 168 echo "\nCaching head<pre>\n"; 169 print_r($this->cacheOPMLHead); 170 echo "\n</pre>\n"; 171 } 172 } elseif (OPMLDEBUG == 1) { 173 echo "\nfalse<br />\n"; 174 } 175 176 } 177 178 return $head['tag'] == 'head' ? $head : false; 179 } 180 181 function getOPMLBody($tree) { 182 $body = array(); 183 184 if (isset($this->cacheOPMLBody) && count($this->cacheOPMLBody) != 0) { 185 $body = $this->cacheOPMLBody; 186 } else { 187 188 if (OPMLDEBUG == 1) { 189 echo "\ngetOPMLBody<br />\n"; 190 } 191 192 $body = $this->getOPMLTag($tree, 'body'); 193 194 if ($body !== false) { 195 $this->cacheOPMLBody = $body; 196 197 if (OPMLDEBUG == 1) { 198 echo "\nCaching body<pre>\n"; 199 print_r($this->cacheOPMLBody); 200 echo "\n</pre>\n"; 201 } 202 203 } elseif (OPMLDEBUG == 1) { 204 echo "\nfalse<br />\n"; 205 } 206 } 207 208 return $body['tag'] == 'body' ? $body : false; 209 } 210 211 function getOPMLOutline($tree, $index) { 212 213 if (isset($this->cacheOPMLOutline[$index])) { 214 return $this->cacheOPMLOutline[$index]; 215 } 216 217 $body = $this->getOPMLBody($tree); 218 219 if (!$body) { 220 return false; 221 } 222 223 $outline = $body['children'][$index]; 224 225 if ($outline['tag'] == 'outline') { 226 $this->cacheOPMLOutline[$index] = $outline; 227 228 if (OPMLDEBUG == 1) { 229 echo "\ngetOPMLOutline[" . $index . "]<br />\n"; 230 echo "\nCaching outline[" . $index . "]<pre>\n"; 231 print_r($this->cacheOPMLOutline[$index]); 232 echo "\n</pre>\n"; 233 } 234 235 return $outline; 236 } else { 237 return false; 238 } 239 } 240 241 function getOPMLOutlineAttr($tree, $index) { 242 $outline = $this->getOPMLOutline($tree, $index); 243 244 return $outline != false ? $outline['attributes'] : false; 245 } 246 247 } 248 249 class serendipity_plugin_remoterss extends serendipity_plugin { 250 var $title = PLUGIN_REMOTERSS_TITLE; 251 var $encoding = null; 252 253 function introspect(&$propbag) { 254 $this->title = $this->get_config('sidebartitle', $this->title); 255 256 $propbag->add('name', PLUGIN_REMOTERSS_TITLE); 257 $propbag->add('description', PLUGIN_REMOTERSS_BLAHBLAH); 258 $propbag->add('stackable', true); 259 $propbag->add('author', 'Udo Gerhards, Richard Thomas Harrison'); 260 $propbag->add('version', '1.10'); 261 $propbag->add('requirements', array( 262 'serendipity' => '0.8', 263 'smarty' => '2.6.7', 264 'php' => '4.1.0' 265 )); 266 $propbag->add('configuration', array('number', 'use_rss_link', 'show_rss_element', 'escape_rss', 'displaydate', 'dateformat', 'sidebartitle', 'rssuri', 'charset', 'target', 'cachetime', 'feedtype', 'bulletimg', 'markup')); 267 $propbag->add('groups', array('FRONTEND_EXTERNAL_SERVICES')); 268 } 269 270 function introspect_config_item($name, &$propbag) { 271 switch($name) { 272 273 case 'use_rss_link': 274 $propbag->add('type', 'boolean'); 275 $propbag->add('name', PLUGIN_REMOTERSS_RSSLINK); 276 $propbag->add('description', PLUGIN_REMOTERSS_RSSLINK_DESC); 277 $propbag->add('default', 'true'); 278 break; 279 280 case 'escape_rss': 281 $propbag->add('type', 'boolean'); 282 $propbag->add('name', PLUGIN_REMOTERSS_RSSESCAPE); 283 $propbag->add('description', PLUGIN_REMOTERSS_RSSESCAPE_DESC); 284 $propbag->add('default', 'true'); 285 break; 286 287 case 'show_rss_element': 288 $propbag->add('type', 'string'); 289 $propbag->add('name', PLUGIN_REMOTERSS_RSSFIELD); 290 $propbag->add('description', PLUGIN_REMOTERSS_RSSFIELD_DESC); 291 $propbag->add('default', 'title'); 292 break; 293 294 case 'markup': 295 $propbag->add('type', 'boolean'); 296 $propbag->add('name', DO_MARKUP); 297 $propbag->add('description', DO_MARKUP_DESCRIPTION); 298 $propbag->add('default', 'false'); 299 break; 300 301 case 'charset': 302 $propbag->add('type', 'radio'); 303 $propbag->add('name', CHARSET); 304 $propbag->add('description', CHARSET); 305 $propbag->add('default', 'native'); 306 307 $charsets = array(); 308 if (LANG_CHARSET != 'UTF-8') { 309 $charsets['value'][] = $charsets['desc'][] = 'UTF-8'; 310 } 311 if (LANG_CHARSET != 'ISO-8859-1') { 312 $charsets['value'][] = $charsets['desc'][] = 'ISO-8859-1'; 313 } 314 315 $charsets['value'][] = 'native'; 316 $charsets['desc'][] = LANG_CHARSET; 317 $propbag->add('radio', $charsets); 318 break; 319 320 case 'feedtype': 321 $select = array('rss' => 'RSS', 'opml' => 'OPML'); 322 $propbag->add('type', 'select'); 323 $propbag->add('name', PLUGIN_REMOTERSS_FEEDTYPE); 324 $propbag->add('description', PLUGIN_REMOTERSS_FEEDTYPE_BLAHBLAH); 325 $propbag->add('select_values', $select); 326 $propbag->add('default', 'rss'); 327 break; 328 329 case 'number': 330 $propbag->add('type', 'string'); 331 $propbag->add('name', PLUGIN_REMOTERSS_NUMBER); 332 $propbag->add('description', PLUGIN_REMOTERSS_NUMBER_BLAHBLAH); 333 $propbag->add('default', '0'); 334 break; 335 336 case 'dateformat': 337 $propbag->add('type', 'string'); 338 $propbag->add('name', GENERAL_PLUGIN_DATEFORMAT); 339 $propbag->add('description', sprintf(GENERAL_PLUGIN_DATEFORMAT_BLAHBLAH, '%A, %B %e. %Y')); 340 $propbag->add('default', '%A, %B %e. %Y'); 341 break; 342 343 case 'sidebartitle': 344 $propbag->add('type', 'string'); 345 $propbag->add('name', PLUGIN_REMOTERSS_SIDEBARTITLE); 346 $propbag->add('description', PLUGIN_REMOTERSS_SIDEBARTITLE_BLAHBLAH); 347 $propbag->add('default', ''); 348 break; 349 350 case 'rssuri': 351 $propbag->add('type', 'string'); 352 $propbag->add('name', PLUGIN_REMOTERSS_RSSURI); 353 $propbag->add('description', PLUGIN_REMOTERSS_RSSURI_BLAHBLAH); 354 $propbag->add('default', ''); 355 break; 356 357 case 'target': 358 $propbag->add('type', 'string'); 359 $propbag->add('name', PLUGIN_REMOTERSS_RSSTARGET); 360 $propbag->add('description', PLUGIN_REMOTERSS_RSSTARGET_BLAHBLAH); 361 $propbag->add('default', '_blank'); 362 break; 363 364 case 'cachetime': 365 $propbag->add('type', 'string'); 366 $propbag->add('name', PLUGIN_REMOTERSS_CACHETIME); 367 $propbag->add('description', PLUGIN_REMOTERSS_CACHETIME_BLAHBLAH); 368 $propbag->add('default', 10800); 369 break; 370 371 case 'bulletimg': 372 $propbag->add('type', 'string'); 373 $propbag->add('name', PLUGIN_REMOTERSS_BULLETIMG); 374 $propbag->add('description', PLUGIN_REMOTERSS_BULLETIMG_BLAHBLAH); 375 $propbag->add('default', ''); 376 break; 377 378 379 case 'displaydate': 380 $propbag->add('type', 'boolean'); 381 $propbag->add('name', PLUGIN_REMOTERSS_DISPLAYDATE); 382 $propbag->add('description', PLUGIN_REMOTERSS_BLAHBLAH); 383 $propbag->add('default', 'true'); 384 break; 385 386 default: 387 return false; 388 } 389 return true; 390 } 391 392 // Check if a given URI is readable. 393 function urlcheck($uri) { 394 395 // These two substring comparisons are faster than one regexp. 396 if ('http://' != substr($uri, 0, 7) && 'https://' != substr($uri, 0, 8)) { 397 return false; 398 } 399 400 // Disabled by now. May get enabled in the future, but for now the extra HTTP call isn't worth trying. 401 return true; 402 require_once S9Y_PEAR_PATH . 'HTTP/Request.php'; 403 serendipity_request_start(); 404 $req = &new HTTP_Request($uri); 405 406 if (PEAR::isError($req->sendRequest()) || !preg_match('@^[23]..@', $req->getResponseCode())) { 407 serendipity_request_end(); 408 return false; 409 } else { 410 serendipity_request_end(); 411 return true; 412 } 413 } 414 415 function debug($msg) { 416 static $debug = false; 417 418 if ($debug === false) { 419 return false; 420 } 421 422 $fp = fopen('rss.log', 'a'); 423 fwrite($fp, '[' . date('Y-m-d H:i') . '] ' . $msg . "\n"); 424 fclose($fp); 425 } 426 427 function generate_content(&$title) { 428 global $serendipity; 429 430 $number = $this->get_config('number'); 431 $displaydate = $this->get_config('displaydate','true'); 432 $dateformat = $this->get_config('dateformat'); 433 $sidebartitle = $title = $this->get_config('sidebartitle', $this->title); 434 $rssuri = $this->get_config('rssuri'); 435 $target = $this->get_config('target'); 436 $cachetime = $this->get_config('cachetime'); 437 $feedtype = $this->get_config('feedtype', 'rss'); 438 $markup = $this->get_config('markup', 'false'); 439 $bulletimg = $this->get_config('bulletimg'); 440 $charset = $this->get_config('charset', 'native'); 441 442 if (!$number || !is_numeric($number) || $number < 1) { 443 $showAll = true; 444 } else { 445 $showAll = false; 446 } 447 448 if (!$dateformat || strlen($dateformat) < 1) { 449 $dateformat = '%A, %B %e. %Y'; 450 } 451 452 if (!$cachetime || !is_numeric($cachetime)) { 453 $cachetime = 10800; // 3 hours in seconds 454 } 455 456 if (trim($rssuri)) { 457 $feedcache = $serendipity['serendipityPath'] . 'templates_c/remoterss_cache_' . md5(preg_replace('@[^a-z0-9]*@i', '', $rssuri)) . '.dat'; 458 if (!file_exists($feedcache) || filesize($feedcache) == 0 || filemtime($feedcache) < (time() - $cachetime)) { 459 $this->debug('Cachefile does not existing.'); 460 if (!$this->urlcheck($rssuri)) { 461 $this->debug('URLCheck failed'); 462 echo '<!-- No valid URL! -->'; 463 } elseif ($feedtype == 'rss') { 464 $this->debug('URLCheck succeeded. Touching ' . $feedcache); 465 // Touching the feedcache file will prevent loops of death when the RSS target is the same URI than our blog. 466 @touch($feedcache); 467 require_once S9Y_PEAR_PATH . 'Onyx/RSS.php'; 468 $c = &new Onyx_RSS($charset); 469 $this->debug('Running Onyx Parser'); 470 $c->parse($rssuri); 471 $this->encoding = $c->rss['encoding']; 472 473 $use_rss_link = serendipity_db_bool($this->get_config('use_rss_link')); 474 $rss_elements = explode(',', $this->get_config('show_rss_element')); 475 $escape_rss = serendipity_db_bool($this->get_config('escape_rss')); 476 $i = 0; 477 $content = ''; 478 while (($showAll || ($i < $number)) && ($item = $c->getNextItem())) { 479 if (empty($item['title'])) { 480 continue; 481 } 482 483 if ($use_rss_link) { 484 $content .= '<a href="' . $this->decode($item['link']) . '" ' . (!empty($target) ? 'target="'.$target.'"' : '') . '>'; 485 } 486 487 if (!empty($bulletimg)) { 488 $content .= '<img src="' . $bulletimg . '" border="0" alt="*" /> '; 489 } 490 491 foreach($rss_elements AS $rss_element) { 492 $rss_element = trim($rss_element); 493 if ($escape_rss) { 494 $content .= $this->decode($item[$rss_element]); 495 } else { 496 $content .= htmlspecialchars($this->decode($item[$rss_element])); 497 } 498 } 499 500 if ($use_rss_link) { 501 $content .= '</a>'; 502 } 503 504 $content .= "<br />\n"; 505 $item['timestamp'] = @strtotime(isset($item['pubdate']) ? $item['pubdate'] : $item['dc:date']); 506 if (!($item['timestamp'] == -1) AND ($displaydate == 'true')) { 507 $content .= '<div class="serendipitySideBarDate">' 508 . htmlspecialchars(serendipity_formatTime($dateformat, $item['timestamp'], false)) 509 . '</div><br />'; 510 511 } 512 ++$i; 513 } 514 515 $this->debug('Caching Feed (' . strlen($content) . ' bytes)'); 516 $fp = @fopen($feedcache, 'w'); 517 if (trim($content) != '' && $fp) { 518 fwrite($fp, $content); 519 fclose($fp); 520 $this->debug('Feed cache written'); 521 } else { 522 $this->debug('Could not write (empty?) cache.'); 523 echo '<!-- Cache failed to ' . $feedcache . ' in ' . getcwd() . ' --><br />'; 524 if (trim($content) == '') { 525 $this->debug('Getting old feedcache'); 526 $content = @file_get_contents($feedcache); 527 } 528 } 529 $this->debug('RSS Plugin finished.'); 530 } elseif ($feedtype == 'opml') { 531 // Touching the feedcache file will prevent loops of death when the RSS target is the same URI than our blog. 532 @touch($feedcache); 533 534 $opml = new s9y_remoterss_OPML(); 535 $opmltree = $opml->parseOPML($rssuri); 536 537 if (OPMLDEBUG == 1) { 538 echo "\n<pre>\n"; 539 print_r($opmltree); 540 echo "\n</pre>\n"; 541 } 542 543 if ($opmltree['tag'] === 'opml') { 544 $head = $opml->getOPMLHead($opmltree); 545 $ownerName = $opml->getOPMLTag($head, 'ownerName'); 546 $blogrolling = $ownerName != false ? ($ownerName['value'] == 'Blogroll Owner' ? true : false) : false; 547 548 $i = 0; 549 $content = ''; 550 while (($showAll || ($i < $number)) && ($item = $opml->getOPMLOutlineAttr($opmltree, $i))) { 551 if (!empty($item['url'])) { 552 $url = $this->decode($item['url']); 553 } elseif (!empty($item['htmlUrl'])) { 554 $url = $this->decode($item['htmlUrl']); 555 } elseif (!empty($item['xmlUrl'])) { 556 $url = $this->decode($item['xmlUrl']); 557 } elseif (!empty($item['urlHTTP'])) { 558 $url = $this->decode($item['urlHTTP']); 559 } else { 560 $url = ''; 561 } 562 563 if (!empty($item['text'])) { 564 $text = htmlspecialchars($this->decode($item['text'])); 565 } elseif (!empty($item['title'])) { 566 $text = htmlspecialchars($this->decode($item['title'])); 567 } elseif (!empty($item['description'])) { 568 $text = htmlspecialchars($this->decode($item['description'])); 569 } else { 570 $text = ''; 571 } 572 573 if ($blogrolling === true && (!empty($text) || !empty($url))) { 574 $content .= '• <a href="' . $url . '" ' . (!empty($target) ? 'target="'.$target.'"' : '') . ' title="' . $text . '">' . htmlspecialchars($text) . "</a>"; 575 if (isset($item['isRecent'])) { 576 $content .= ' <span style="color: Red; ">*</span>'; 577 } 578 $content .= "<br />"; 579 } elseif ((isset($item['type']) && $item['type'] == 'url') || !empty($url)) { 580 $content .= '• <a href="' .$url . '" ' . (!empty($target) ? 'target="'.$target.'"' : '') . ' title="' . $text . '">' . $text . "</a>"; 581 $content .= "<br />"; 582 } 583 ++$i; 584 } 585 586 /* Pretend to be a html_nugget so we can apply markup events. */ 587 if ($markup == 'true') { 588 $entry = array('html_nugget' => $content); 589 serendipity_plugin_api::hook_event('frontend_display', $entry); 590 $content = $entry['html_nugget']; 591 } 592 593 $fp = @fopen($feedcache, 'w'); 594 if (trim($content) != '' && $fp) { 595 fwrite($fp, $content); 596 fclose($fp); 597 } else { 598 echo '<!-- Cache failed to ' . $feedcache . ' in ' . getcwd() . ' --><br />'; 599 if (trim($content) == '') { 600 $content = @file_get_contents($feedcache); 601 } 602 } 603 } else { 604 echo '<!-- Not a valid OPML feed -->'; 605 } 606 } else { 607 echo '<!-- no valid feedtype -->'; 608 } 609 } else { 610 $this->debug('Got feed from cache ' . $feedcache); 611 $content = file_get_contents($feedcache); 612 } 613 614 echo $content; 615 } else { 616 echo PLUGIN_REMOTERSS_NOURI; 617 } 618 } 619 620 function &decode($string) { 621 $target = $this->get_config('charset', 'native'); 622 623 // xml_parser_* functions to recoding from ISO-8859-1/UTF-8 624 if (LANG_CHARSET == 'ISO-8859-1' || LANG_CHARSET == 'UTF-8') { 625 return $string; 626 } 627 628 switch($target) { 629 case 'native': 630 return $string; 631 632 case 'ISO-8859-1': 633 if (function_exists('iconv')) { 634 $out = iconv('ISO-8859-1', LANG_CHARSET, $string); 635 } elseif (function_exists('recode')) { 636 $out = recode('iso-8859-1..' . LANG_CHARSET, $string); 637 } else { 638 return $string; 639 } 640 641 return $out; 642 643 case 'UTF-8': 644 default: 645 $out = utf8_decode($string); 646 return $out; 647 } 648 } 649 } 650 651 /* vim: set sts=4 ts=4 expandtab : */
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sat Nov 24 09:00:37 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |