Advertisement
Guest User

Untitled

a guest
Apr 26th, 2020
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.38 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4. *
  5. * Feed post bot main class
  6. *
  7. * @copyright (c) 2017 Ger Bruinsma
  8. * @license GNU General Public License, version 2 (GPL-2.0)
  9. *
  10. */
  11.  
  12. namespace ger\feedpostbot\classes;
  13.  
  14. class driver
  15. {
  16. protected $config;
  17. protected $config_text;
  18. protected $user;
  19. protected $language;
  20. protected $auth;
  21. protected $db;
  22. protected $log;
  23. protected $phpbb_root_path;
  24. protected $php_ext;
  25. protected $phpbb_dispatcher;
  26. public $current_state;
  27.  
  28. /**
  29. * Constructor
  30. *
  31. * @param \phpbb\config\config $config Config object
  32. * @param \phpbb\config\db_text $config_text Config text object
  33. * @param \phpbb\request\request_interface $request Request object
  34. * @param \phpbb\user $user User object
  35. * @param \phpbb\language\language $language Language object
  36. * @param \phpbb\auth\auth $auth Auth object
  37. * @param \phpbb\db\driver\driver_interface $db DB object
  38. * @param string $phpbb_root_path
  39. * @param string $php_ext
  40. * @param \phpbb\event\dispatcher $phpbb_dispatcher
  41. */
  42. public function __construct(\phpbb\config\config $config, \phpbb\config\db_text $config_text, \phpbb\user $user, \phpbb\language\language $language, \phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db, \phpbb\log\log $log, $phpbb_root_path, $php_ext, \phpbb\event\dispatcher $phpbb_dispatcher)
  43. {
  44. $this->config = $config;
  45. $this->config_text = $config_text;
  46. $this->user = $user;
  47. $this->language = $language;
  48. $this->auth = $auth;
  49. $this->db = $db;
  50. $this->log = $log;
  51. $this->phpbb_root_path = $phpbb_root_path;
  52. $this->php_ext = $php_ext;
  53. $this->phpbb_dispatcher = $phpbb_dispatcher;
  54. }
  55.  
  56. /**
  57. * Set and return current state
  58. */
  59. public function init_current_state()
  60. {
  61. $ct = $this->config_text->get('ger_feedpostbot_current_state');
  62. if (empty($ct) || $ct === 'null')
  63. {
  64. $this->current_state = false;
  65. }
  66. else
  67. {
  68. $this->current_state = json_decode($ct, true);
  69. $this->check_state_parameters();
  70. }
  71. return $this->current_state;
  72. }
  73.  
  74. /**
  75. * Make sure we have all parameters set
  76. */
  77. private function check_state_parameters()
  78. {
  79. $new_state = [];
  80. foreach($this->current_state as $id => $source)
  81. {
  82. if (isset($source['append_link']))
  83. {
  84. $new_state[$id] = $source;
  85. }
  86. else
  87. {
  88. $new = $source;
  89. $new['append_link'] = 1;
  90. $new_state[$id] = $new;
  91. }
  92. }
  93. $this->current_state = $new_state;
  94. $this->config_text->set('ger_feedpostbot_current_state', json_encode($new_state));
  95. }
  96.  
  97. /**
  98. * Fetch all feeds
  99. * This is called by the cron handler
  100. * @return int
  101. */
  102. public function fetch_all()
  103. {
  104. if (empty($this->current_state))
  105. {
  106. $this->init_current_state();
  107. }
  108. $lock = (int) $this->config['feedpostbot_locked'];
  109. if ($lock > 0)
  110. {
  111. return 0;
  112. }
  113. $counter = 0;
  114. $active_user = $this->user->data['user_id'];
  115. if (empty($this->current_state))
  116. {
  117. return 0;
  118. }
  119. if (!$this->config->set_atomic('feedpostbot_locked', 0, time(), false))
  120. {
  121. return 0;
  122. }
  123. foreach($this->current_state as $id => $source)
  124. {
  125. // Only proceed if not disabled in ACP
  126. if ($source['forum_id'] > 0)
  127. {
  128. $counter += $this->fetch_items($this->parse_feed($source['url'], $source['type'], $source['timeout']), $id);
  129. }
  130. }
  131. $this->config_text->set('ger_feedpostbot_current_state', json_encode($this->current_state));
  132. $this->switch_user($active_user);
  133. $this->config->set('feedpostbot_locked', 0, false);
  134. return $counter;
  135. }
  136.  
  137.  
  138. /**
  139. * Get content through curl or fallback to file_get_contents
  140. * @param string $url
  141. * @param int $timeout
  142. * @param bool $useragent_override
  143. * @param bool $force_file_get_contents
  144. * @return string with content data or false
  145. */
  146. private function get_content($url, $timeout = 10, $useragent_override = false, $force_file_get_contents = false)
  147. {
  148. $url= html_entity_decode($url);
  149. if (!function_exists('curl_init') || $force_file_get_contents)
  150. {
  151. $opts['http']['timout'] = (int) $timeout;
  152. $context = stream_context_create($opts);
  153. $data = @file_get_contents($url, false, $context); // Suppress errors
  154. }
  155. else
  156. {
  157. $curl = curl_init($url);
  158.  
  159. curl_setopt($curl, CURLOPT_FAILONERROR, true);
  160. curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
  161. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  162. curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
  163. if ($useragent_override)
  164. {
  165. curl_setopt($curl, CURLOPT_USERAGENT, 'Googlebot/2.1 (+http://www.google.com/bot.html)' );
  166. }
  167. $data = curl_exec($curl);
  168. curl_close($curl);
  169. }
  170. if (empty($data))
  171. {
  172. // Try it posing as Google
  173. if (!$useragent_override)
  174. {
  175. return $this->get_content($url, $timeout, true);
  176. }
  177. return $this->get_content($url, $timeout, false, true);
  178. }
  179. return $data;
  180. }
  181.  
  182. /**
  183. * Parse a feed
  184. * @param string $url
  185. * @param string $type
  186. * @param int $timeout
  187. * @return boolean
  188. */
  189. private function parse_feed($url, $type, $timeout = 3)
  190. {
  191. // Don't throw errors but log them instead
  192. libxml_use_internal_errors(true);
  193.  
  194. $data = $this->get_content($url, $timeout);
  195. if (!$data)
  196. {
  197. $this->log->add('critical', $this->user->data['user_id'], $this->user->ip, 'FPB_LOG_FEED_TIMEOUT', time(), array($url . ' (' . $timeout . ' s)'));
  198. return false;
  199. }
  200. else
  201. {
  202. $method = 'parse_'.$type;
  203. return $this->$method($data, $url);
  204. }
  205. }
  206.  
  207. /**
  208. * Autodetect feed type
  209. */
  210. public function detect_feed_type($url)
  211. {
  212. $data = $this->get_content($url);
  213.  
  214. if (!empty($data))
  215. {
  216. // Determine feed type and proceed accordingly
  217. if ((stripos($data, 'application/atom+xml')!== false) || preg_match('/xmlns="(.+?)Atom"/i', $data))
  218. {
  219. return 'atom';
  220. }
  221. else if (stripos($data, '<rdf:RDF') !== false)
  222. {
  223. return 'rdf';
  224. }
  225. else
  226. {
  227. return 'rss';
  228. }
  229. }
  230. return false;
  231. }
  232.  
  233. /**
  234. * Parse the atom source into relevant info
  235. * @param string $data valid ATOM XML string
  236. * @return array
  237. */
  238. private function parse_atom($data, $url)
  239. {
  240. $content = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
  241. if ($content === false)
  242. {
  243. $this->log_xml_error($url);
  244. return false;
  245. }
  246. $ns = $content->getNamespaces(true);
  247.  
  248. foreach($content->entry as $item)
  249. {
  250. $append = array(
  251. 'guid' => $this->prop_to_string($item->id),
  252. 'title' => $this->prop_to_string($item->title),
  253. 'link' => $this->prop_to_string($item->link->attributes()->href),
  254. 'description' => $this->get_item_description($item, $ns),
  255. 'pubDate' => empty($item->updated) ? 0 : $this->prop_to_string($item->updated),
  256. );
  257.  
  258. /**
  259. * Modify the fetched ATOM item before it's added to the return list
  260. *
  261. * @event ger.feedpostbot.parse_atom_append
  262. * @var object item item as found in source
  263. * @var array append Array of properties to be send to the post_message function
  264. * @since 1.0.1
  265. */
  266. $vars = array('item', 'append');
  267. extract($this->phpbb_dispatcher->trigger_event('ger.feedpostbot.parse_atom_append', compact($vars)));
  268.  
  269. // Add it to the list
  270. $return[] = $append;
  271. }
  272.  
  273. $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'FPB_LOG_FEED_FETCHED', time(), array($url));
  274. return $return;
  275. }
  276.  
  277. /**
  278. * Parse the RDF source into relevant info
  279. * @param string $data valid RDF XML string
  280. * @return array
  281. */
  282. private function parse_rdf($data, $url)
  283. {
  284. // RDF default hasn't dates. Most use a DC or SY namespace but SimpleXML doesn't handle those
  285. $find = array('dc:date>', 'sy:date>');
  286.  
  287. $content = simplexml_load_string(str_replace($find, 'date>', $data), 'SimpleXMLElement', LIBXML_NOCDATA);
  288. if ($content === false)
  289. {
  290. $this->log_xml_error($url);
  291. return false;
  292. }
  293. $ns = $content->getNamespaces(true);
  294.  
  295. foreach($content->item as $item)
  296. {
  297. $append = array(
  298. 'title' => $this->prop_to_string($item->title),
  299. 'link' => $this->prop_to_string($item->link),
  300. 'description' => $this->get_item_description($item, $ns),
  301. 'pubDate' => empty($item->date) ? ( empty($content->channel->date) ? 0 : $this->prop_to_string($content->channel->date) ) : $this->prop_to_string($item->date), // Fallback galore
  302. );
  303.  
  304. /**
  305. * Modify the fetched RDF item before it's added to the return list
  306. *
  307. * @event ger.feedpostbot.parse_rdf_append
  308. * @var object item item as found in source
  309. * @var array append Array of properties to be send to the post_message function
  310. * @since 1.0.1
  311. */
  312. $vars = array('item', 'append');
  313. extract($this->phpbb_dispatcher->trigger_event('ger.feedpostbot.parse_rdf_append', compact($vars)));
  314.  
  315. // Add it to the list
  316. $return[] = $append;
  317. }
  318. $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'FPB_LOG_FEED_FETCHED', time(), array($url));
  319. return $return;
  320. }
  321.  
  322. /**
  323. * Parse the RSS source into relevant info
  324. * @param string $data valid RSS XML string
  325. * @return array
  326. */
  327. private function parse_rss($data, $url)
  328. {
  329. $content = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
  330. if ($content === false)
  331. {
  332. $this->log_xml_error($url);
  333. return false;
  334. }
  335. $ns = $content->getNamespaces(true);
  336.  
  337. foreach($content->channel->item as $item)
  338. {
  339. $append = array(
  340. 'guid' => $this->prop_to_string($item->guid),
  341. 'title' => $this->prop_to_string($item->title),
  342. 'link' => $this->prop_to_string($item->link),
  343. 'description' => $this->get_item_description($item, $ns),
  344. 'pubDate' => $this->prop_to_string($item->pubDate),
  345. );
  346.  
  347. /**
  348. * Modify the fetched RSS item before it's added to the return list
  349. *
  350. * @event ger.feedpostbot.parse_rss_append
  351. * @var object item item as found in source
  352. * @var array append Array of properties to be send to the post_message function
  353. * @since 1.0.1
  354. */
  355. $vars = array('item', 'append');
  356. extract($this->phpbb_dispatcher->trigger_event('ger.feedpostbot.parse_rss_append', compact($vars)));
  357.  
  358. // Add it to the list
  359. $return[] = $append;
  360. }
  361. $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'FPB_LOG_FEED_FETCHED', time(), array($url));
  362. return $return;
  363.  
  364. }
  365.  
  366. /**
  367. * Get some description with fallbacks for fallbacks
  368. * @param object $item
  369. * @param object $ns
  370. * @return string
  371. */
  372. private function get_item_description($item, $ns = null)
  373. {
  374. if ( (!empty($ns['content'])) && $item->children($ns['content'])->encoded)
  375. {
  376. return $this->prop_to_string($item->children($ns['content'])->encoded);
  377. }
  378. if (!empty($item->description))
  379. {
  380. return $this->prop_to_string($item->description);
  381. }
  382. if (!empty($item->content))
  383. {
  384. return $this->prop_to_string($item->content);
  385. }
  386. if (!empty($item->summary))
  387. {
  388. return $this->prop_to_string($item->summary);
  389. }
  390. if (!empty($item->title))
  391. {
  392. return $this->prop_to_string($item->title);
  393. }
  394. // Still here?
  395. return '';
  396. }
  397.  
  398.  
  399. /**
  400. * Fetch the new content in feed
  401. *
  402. * @param array $items
  403. * @param int $source_id
  404. * @return int
  405. */
  406. public function fetch_items($items, $source_id)
  407. {
  408. $posted = 0;
  409. if (empty($items))
  410. {
  411. return $posted;
  412. }
  413.  
  414. $new_latest = array(
  415. 'link' => $this->prop_to_string($items[0]['link']),
  416. 'pubDate' => $this->prop_to_string($items[0]['pubDate']),
  417. 'guid' => empty($items[0]['guid']) ? '' : $items[0]['guid'],
  418. );
  419.  
  420. $to_post = array();
  421. foreach($items as $item)
  422. {
  423. if ($this->is_handled($item, $this->current_state[$source_id]['latest']))
  424. {
  425. // We've had this one and all below
  426. $this->current_state[$source_id]['latest'] = $new_latest;
  427. break;
  428. }
  429. else
  430. {
  431. $to_post[] = $item;
  432. }
  433. }
  434. if (!empty($to_post))
  435. {
  436. $this->switch_user($this->current_state[$source_id]['user_id']);
  437.  
  438. // Reverse array to make sure that the latest item is also the newest
  439. $to_post = array_reverse($to_post);
  440. foreach($to_post as $item)
  441. {
  442. $this->post_message($item, $source_id);
  443. $posted++;
  444. }
  445. }
  446.  
  447. $this->current_state[$source_id]['latest'] = $new_latest;
  448. return $posted;
  449. }
  450.  
  451. /**
  452. * Check if this is the latest item
  453. * Use guid if available, fallback to pubDate & link
  454. * @param object $item
  455. * @param array $current
  456. * @return bool
  457. */
  458. private function is_handled($item, $current)
  459. {
  460. if ( (empty($current['link'])) && (empty($current['pubDate'])) && (empty($current['guid'])) )
  461. {
  462. return false;
  463. }
  464. if (!empty($item['guid']) && ($this->prop_to_string($item['guid']) == $current['guid']))
  465. {
  466. return true;
  467. }
  468. else if (($item['pubDate'] == $current['pubDate']) && ($item['link'] == $current['link']))
  469. {
  470. return true;
  471. }
  472. return false;
  473. }
  474.  
  475. /**
  476. * Create a topic for new RSS item
  477. *
  478. * @param array $rss_item
  479. * @param int $source_id
  480. * @return string
  481. */
  482. private function post_message($rss_item, $source_id)
  483. {
  484. if (empty($rss_item))
  485. {
  486. return false;
  487. }
  488. if (!function_exists('generate_text_for_storage'))
  489. {
  490. include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext);
  491. }
  492. if (!function_exists('submit_post'))
  493. {
  494. include($this->phpbb_root_path . 'includes/functions_posting.' . $this->php_ext);
  495. }
  496.  
  497. // Make sure we have UTF-8 and handle HTML
  498. $description = $rss_item['description'];
  499. $title = $this->clean_title($rss_item['title']);
  500. if (!empty($this->current_state[$source_id]['prefix']))
  501. {
  502. $title = trim($this->current_state[$source_id]['prefix']) . ' ' . $title;
  503. }
  504.  
  505. // Only show excerpt of feed if a text limit is given, but make it nice
  506. if (!empty($this->current_state[$source_id]['textlimit']))
  507. {
  508. $post_text = $this->html2bbcode($this->closetags($this->character_limiter($description, $this->current_state[$source_id]['textlimit'])));
  509. if (!empty($this->current_state[$source_id]['append_link']))
  510. {
  511. $post_text .= "\n\n" . '[url=' . $rss_item['link'] . ']' . $this->user->lang('FPB_READ_MORE') . '[/url]';
  512. }
  513. }
  514. else
  515. {
  516. $post_text = $this->html2bbcode($description);
  517. if (!empty($this->current_state[$source_id]['append_link']))
  518. {
  519. $post_text .= "\n\n" . $this->user->lang('FPB_SOURCE') . ' [url]' . $rss_item['link'] . '[/url]';
  520. }
  521. }
  522.  
  523. $poll = $uid = $bitfield = $options = '';
  524. $allow_bbcode = $allow_urls = $allow_smilies = true;
  525. generate_text_for_storage($post_text, $uid, $bitfield, $options, $allow_bbcode, $allow_urls, $allow_smilies);
  526.  
  527. $data = array(
  528. // General Posting Settings
  529. 'forum_id' => $this->current_state[$source_id]['forum_id'], // The forum ID in which the post will be placed. (int)
  530. 'topic_id' => 0, // Post a new topic or in an existing one? Set to 0 to create a new one, if not, specify your topic ID here instead.
  531. 'icon_id' => false, // The Icon ID in which the post will be displayed with on the viewforum, set to false for icon_id. (int)
  532. // Defining Post Options
  533. 'enable_bbcode' => true, // Enable BBcode in this post. (bool)
  534. 'enable_smilies' => true, // Enabe smilies in this post. (bool)
  535. 'enable_urls' => true, // Enable self-parsing URL links in this post. (bool)
  536. 'enable_sig' => true, // Enable the signature of the poster to be displayed in the post. (bool)
  537. // Message Body
  538. 'message' => $post_text, // Your text you wish to have submitted. It should pass through generate_text_for_storage() before this. (string)
  539. 'message_md5' => md5($post_text), // The md5 hash of your message
  540. // Values from generate_text_for_storage()
  541. 'bbcode_bitfield' => $bitfield, // Value created from the generate_text_for_storage() function.
  542. 'bbcode_uid' => $uid, // Value created from the generate_text_for_storage() function.
  543. // Other Options
  544. 'post_edit_locked' => 0, // Disallow post editing? 1 = Yes, 0 = No
  545. 'topic_title' => $title,
  546. 'notify_set' => true, // (bool)
  547. 'notify' => true, // (bool)
  548. 'post_time' => empty($this->current_state[$source_id]['curdate']) ? strtotime($rss_item['pubDate']) : 0, // Set a specific time, use 0 to let submit_post() take care of getting the proper time (int)
  549. 'forum_name' => $this->get_forum_name($this->current_state[$source_id]['forum_id']), // For identifying the name of the forum in a notification email. (string) // Indexing
  550. 'enable_indexing' => true, // Allow indexing the post? (bool) // 3.0.6
  551. );
  552.  
  553. /**
  554. * Modify the post data array before post is submitted
  555. *
  556. * @event ger.feedpostbot.submit_post_before
  557. * @var array data Data array send to the submit_post function
  558. * @var array rss_item Complete feed item as fetched by parse_{method}
  559. * @since 1.0.1
  560. */
  561. $vars = array('data', 'rss_item');
  562. extract($this->phpbb_dispatcher->trigger_event('ger.feedpostbot.submit_post_before', compact($vars)));
  563.  
  564. return submit_post('post', $data['topic_title'], $this->user->data['username'], POST_NORMAL, $poll, $data);
  565. }
  566.  
  567. /**
  568. * Make sure we have a string
  569. * @param mixed $prop
  570. * @return string
  571. */
  572. private function prop_to_string($prop)
  573. {
  574. if (empty($prop))
  575. {
  576. return '';
  577. }
  578. if (!is_string($prop))
  579. {
  580. // Most probaly a SimpleXMLElement
  581. $prop_ary = (array) $prop;
  582. $prop = $prop_ary[0];
  583. }
  584. $prop = (string) $prop;
  585. return html_entity_decode($prop);
  586. }
  587.  
  588. /**
  589. * Ditch emojis from title
  590. * @param string $string
  591. * @return string
  592. */
  593. private function clean_title($string)
  594. {
  595. return trim(preg_replace('/[\x{10000}-\x{10FFFF}]/u', " ", $string));
  596. }
  597.  
  598. /**
  599. * Switch to the RSS source user
  600. * @param int $new_user_id
  601. * @return bool
  602. */
  603. private function switch_user($new_user_id)
  604. {
  605. if ($this->user->data['user_id'] == $new_user_id)
  606. {
  607. $this->language->add_lang('info_acp_feedpostbot', 'ger/feedpostbot');
  608. return true;
  609. }
  610. $cur_lang = $this->user->data['user_lang'];
  611.  
  612. $sql = 'SELECT *
  613. FROM ' . USERS_TABLE . '
  614. WHERE user_id = ' . (int) $new_user_id;
  615. $result = $this->db->sql_query($sql);
  616. $row = $this->db->sql_fetchrow($result);
  617. $this->db->sql_freeresult($result);
  618. $row['is_registered'] = true;
  619. $this->user->data = array_merge($this->user->data, $row);
  620.  
  621. if ($cur_lang != $row['user_lang'])
  622. {
  623. $this->language->set_user_language($row['user_lang'], true);
  624. }
  625. $this->auth->acl($this->user->data);
  626. $this->language->add_lang('info_acp_feedpostbot', 'ger/feedpostbot');
  627. return true;
  628. }
  629.  
  630. /**
  631. * Get forum name by id (for notifications)
  632. * @param int $id
  633. * @return string
  634. */
  635. private function get_forum_name($id)
  636. {
  637. $sql = 'SELECT forum_name
  638. FROM ' . FORUMS_TABLE . '
  639. WHERE forum_id = ' . (int) $id;
  640. $result = $this->db->sql_query($sql);
  641. $row = $this->db->sql_fetchrow($result);
  642. return empty($row['forum_name']) ? '' : $row['forum_name'];
  643. }
  644.  
  645. /**
  646. * Elegant word wrap
  647. * @param string $str
  648. * @param int $n
  649. * @param string $end_char
  650. * @return string
  651. */
  652. private function character_limiter($str, $n = 300, $end_char = '...')
  653. {
  654. if (strlen($str) < $n)
  655. {
  656. return $str;
  657. }
  658.  
  659. $str = preg_replace("/\s+/", ' ', str_replace(array(
  660. "\r\n",
  661. "\r",
  662. "\n"), ' ', $str));
  663.  
  664. if (strlen($str) <= $n)
  665. {
  666. return $str;
  667. }
  668.  
  669. $out = "";
  670. foreach (explode(' ', trim($str)) as $val)
  671. {
  672. $out .= $val . ' ';
  673.  
  674. if (strlen($out) >= $n)
  675. {
  676. $out = trim($out);
  677. return (strlen($out) == strlen($str)) ? $out : $out . $end_char;
  678. }
  679. }
  680. }
  681.  
  682. /**
  683. * Close open HTML tags
  684. * @param string $html
  685. * @return string
  686. */
  687. private function closetags($html)
  688. {
  689. // put all opened tags into an array
  690. preg_match_all("#<([a-z]+)( .*)?(?!/)>#iU", $html, $result);
  691. $openedtags = $result[1];
  692.  
  693. // put all closed tags into an array
  694. preg_match_all("#</([a-z]+)>#iU", $html, $result);
  695. $closedtags = $result[1];
  696. $len_opened = count($openedtags);
  697.  
  698. // all tags are closed
  699. if (count($closedtags) == $len_opened)
  700. {
  701. return $html;
  702. }
  703.  
  704. $openedtags = array_reverse($openedtags);
  705. // close tags
  706. for ($i = 0; $i < $len_opened; $i++)
  707. {
  708. if (!in_array($openedtags[$i], $closedtags))
  709. {
  710. $html .= "</" . $openedtags[$i] . ">";
  711. }
  712. else
  713. {
  714. unset($closedtags[array_search($openedtags[$i], $closedtags)]);
  715. }
  716. }
  717. return $html;
  718. }
  719.  
  720.  
  721. /**
  722. * Simple HTML to BBcode conversion
  723. * @param string $html_string
  724. * @return string
  725. */
  726. private function html2bbcode($html_string)
  727. {
  728. $convert = array(
  729. "/[\r\n]+/" => " ",
  730. "/\<ul(.*?)\>(.*?)\<\/ul\>/is" => "[list]$2[/list]",
  731. "/\<ol(.*?)\>(.*?)\<\/ol\>/is" => "[list]$2[/list]",
  732. "/\<b(.*?)\>(.*?)\<\/b\>/is" => "[b]$2[/b]",
  733. "/\<i(.*?)\>(.*?)\<\/i\>/is" => "[i]$2[/i]",
  734. "/\<u(.*?)\>(.*?)\<\/u\>/is" => "[u]$2[/u]",
  735. "/\<li(.*?)\>(.*?)\<\/li\>/is" => "[*]$2",
  736. '/\<img(.*?) src=["\']?([^"\'>]+)["\']?(.*?)\>/is' => "[img]$2[/img]",
  737. "/\<div(.*?)\>(.*?)\<\/div\>/is" => "$2",
  738. "/[\s]*\<br(.*?)\>[\s]*/is" => "\n",
  739. "/\<strong(.*?)\>(.*?)\<\/strong\>/is" => "[b]$2[/b]",
  740. '/<a(.+?)href=["\']?([^"\'>]+)["\']?(.*?)>(.*?)\<\/a\>/is' => "[url=$2]$4[/url]",
  741. '/\<iframe (.*?)src=["\']?([^"\'>]+)["\']?(.*?)<\/iframe\>/is' => "\n$2\n",
  742. );
  743.  
  744. // Replace main stuff and strip anything else
  745. return strip_tags(preg_replace(array_keys($convert), array_values($convert), $html_string));
  746. }
  747. /**
  748. * Log xml error messages and clear
  749. * @param string $url
  750. * @return void
  751. */
  752. private function log_xml_error($url)
  753. {
  754. // Create a simple list of found errors
  755. $xml_errors = '';
  756. foreach( libxml_get_errors() as $error )
  757. {
  758. $xml_errors .= $error->message . '\n';
  759. }
  760. $this->log->add('critical', $this->user->data['user_id'], $this->user->ip, 'FPB_LOG_FEED_ERROR', time(), array($url, $xml_errors));
  761.  
  762. // Clear libxml error buffer
  763. libxml_clear_errors();
  764. return;
  765. }
  766. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement