PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/forum/Sources/News.php

https://github.com/leftnode/nooges.com
PHP | 936 lines | 709 code | 104 blank | 123 comment | 181 complexity | 51037cd97ccaac6f5822669d9800d0a1 MD5 | raw file
  1. <?php
  2. /**********************************************************************************
  3. * News.php *
  4. ***********************************************************************************
  5. * SMF: Simple Machines Forum *
  6. * Open-Source Project Inspired by Zef Hemel (zef@zefhemel.com) *
  7. * =============================================================================== *
  8. * Software Version: SMF 2.0 RC2 *
  9. * Software by: Simple Machines (http://www.simplemachines.org) *
  10. * Copyright 2006-2009 by: Simple Machines LLC (http://www.simplemachines.org) *
  11. * 2001-2006 by: Lewis Media (http://www.lewismedia.com) *
  12. * Support, News, Updates at: http://www.simplemachines.org *
  13. ***********************************************************************************
  14. * This program is free software; you may redistribute it and/or modify it under *
  15. * the terms of the provided license as published by Simple Machines LLC. *
  16. * *
  17. * This program is distributed in the hope that it is and will be useful, but *
  18. * WITHOUT ANY WARRANTIES; without even any implied warranty of MERCHANTABILITY *
  19. * or FITNESS FOR A PARTICULAR PURPOSE. *
  20. * *
  21. * See the "license.txt" file for details of the Simple Machines license. *
  22. * The latest version can always be found at http://www.simplemachines.org. *
  23. **********************************************************************************/
  24. if (!defined('SMF'))
  25. die('Hacking attempt...');
  26. /* This file contains the files necessary to display news as an XML feed.
  27. void ShowXmlFeed()
  28. - is called to output xml information.
  29. - can be passed four subactions which decide what is output: 'recent'
  30. for recent posts, 'news' for news topics, 'members' for recently
  31. registered members, and 'profile' for a member's profile.
  32. - To display a member's profile, a user id has to be given. (;u=1)
  33. - uses the Stats language file.
  34. - outputs an rss feed instead of a proprietary one if the 'type' get
  35. parameter is 'rss' or 'rss2'.
  36. - does not use any templates, sub templates, or template layers.
  37. - is accessed via ?action=.xml.
  38. void dumpTags(array data, int indentation, string tag = use_array,
  39. string format)
  40. - formats data retrieved in other functions into xml format.
  41. - additionally formats data based on the specific format passed.
  42. - the data parameter is the array to output as xml data.
  43. - indentation is the amount of indentation to use.
  44. - if a tag is specified, it will be used instead of the keys of data.
  45. - this function is recursively called to handle sub arrays of data.
  46. array getXmlMembers(string format)
  47. - is called to retrieve list of members from database.
  48. - the array will be generated to match the format.
  49. - returns array of data.
  50. array getXmlNews(string format)
  51. - is called to retrieve news topics from database.
  52. - the array will be generated to match the format.
  53. - returns array of topics.
  54. array getXmlRecent(string format)
  55. - is called to retrieve list of recent topics.
  56. - the array will be generated to match the format.
  57. - returns an array of recent posts.
  58. array getXmlProfile(string format)
  59. - is called to retrieve profile information for member into array.
  60. - the array will be generated to match the format.
  61. - returns an array of data.
  62. */
  63. // Show an xml file representing recent information or a profile.
  64. function ShowXmlFeed()
  65. {
  66. global $board, $board_info, $context, $scripturl, $txt, $modSettings, $user_info;
  67. global $query_this_board, $smcFunc, $forum_version, $cdata_override;
  68. // If it's not enabled, die.
  69. if (empty($modSettings['xmlnews_enable']))
  70. obExit(false);
  71. loadLanguage('Stats');
  72. // Default to latest 5. No more than 255, please.
  73. $_GET['limit'] = empty($_GET['limit']) || (int) $_GET['limit'] < 1 ? 5 : min((int) $_GET['limit'], 255);
  74. // Handle the cases where a board, boards, or category is asked for.
  75. $query_this_board = 1;
  76. if (!empty($_REQUEST['c']) && empty($board))
  77. {
  78. $_REQUEST['c'] = explode(',', $_REQUEST['c']);
  79. foreach ($_REQUEST['c'] as $i => $c)
  80. $_REQUEST['c'][$i] = (int) $c;
  81. if (count($_REQUEST['c']) == 1)
  82. {
  83. $request = $smcFunc['db_query']('', '
  84. SELECT name
  85. FROM {db_prefix}categories
  86. WHERE id_cat = {int:current_category}',
  87. array(
  88. 'current_category' => (int) $_REQUEST['c'][0],
  89. )
  90. );
  91. list ($feed_title) = $smcFunc['db_fetch_row']($request);
  92. $smcFunc['db_free_result']($request);
  93. $feed_title = ' - ' . strip_tags($feed_title);
  94. }
  95. $request = $smcFunc['db_query']('', '
  96. SELECT b.id_board, b.num_posts
  97. FROM {db_prefix}boards AS b
  98. WHERE b.id_cat IN ({array_int:current_category_list})
  99. AND {query_see_board}',
  100. array(
  101. 'current_category_list' => $_REQUEST['c'],
  102. )
  103. );
  104. $total_cat_posts = 0;
  105. $boards = array();
  106. while ($row = $smcFunc['db_fetch_assoc']($request))
  107. {
  108. $boards[] = $row['id_board'];
  109. $total_cat_posts += $row['num_posts'];
  110. }
  111. $smcFunc['db_free_result']($request);
  112. if (!empty($boards))
  113. $query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')';
  114. // Try to limit the number of messages we look through.
  115. if ($total_cat_posts > 100 && $total_cat_posts > $modSettings['totalMessages'] / 15)
  116. $query_this_board .= '
  117. AND m.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 400 - $_GET['limit'] * 5);
  118. }
  119. elseif (!empty($_REQUEST['boards']))
  120. {
  121. $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
  122. foreach ($_REQUEST['boards'] as $i => $b)
  123. $_REQUEST['boards'][$i] = (int) $b;
  124. $request = $smcFunc['db_query']('', '
  125. SELECT b.id_board, b.num_posts, b.name
  126. FROM {db_prefix}boards AS b
  127. WHERE b.id_board IN ({array_int:board_list})
  128. AND {query_see_board}
  129. LIMIT ' . count($_REQUEST['boards']),
  130. array(
  131. 'board_list' => $_REQUEST['boards'],
  132. )
  133. );
  134. // Either the board specified doesn't exist or you have no access.
  135. if ($smcFunc['db_num_rows']($request) == 0)
  136. fatal_lang_error('no_board');
  137. $total_posts = 0;
  138. $boards = array();
  139. while ($row = $smcFunc['db_fetch_assoc']($request))
  140. {
  141. if (count($_REQUEST['boards']) == 1)
  142. $feed_title = ' - ' . strip_tags($row['name']);
  143. $boards[] = $row['id_board'];
  144. $total_posts += $row['num_posts'];
  145. }
  146. $smcFunc['db_free_result']($request);
  147. if (!empty($boards))
  148. $query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')';
  149. // The more boards, the more we're going to look through...
  150. if ($total_posts > 100 && $total_posts > $modSettings['totalMessages'] / 12)
  151. $query_this_board .= '
  152. AND m.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 500 - $_GET['limit'] * 5);
  153. }
  154. elseif (!empty($board))
  155. {
  156. $request = $smcFunc['db_query']('', '
  157. SELECT num_posts
  158. FROM {db_prefix}boards
  159. WHERE id_board = {int:current_board}
  160. LIMIT 1',
  161. array(
  162. 'current_board' => $board,
  163. )
  164. );
  165. list ($total_posts) = $smcFunc['db_fetch_row']($request);
  166. $smcFunc['db_free_result']($request);
  167. $feed_title = ' - ' . strip_tags($board_info['name']);
  168. $query_this_board = 'b.id_board = ' . $board;
  169. // Try to look through just a few messages, if at all possible.
  170. if ($total_posts > 80 && $total_posts > $modSettings['totalMessages'] / 10)
  171. $query_this_board .= '
  172. AND m.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 600 - $_GET['limit'] * 5);
  173. }
  174. else
  175. {
  176. $query_this_board = '{query_see_board}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
  177. AND b.id_board != ' . $modSettings['recycle_board'] : ''). '
  178. AND m.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 100 - $_GET['limit'] * 5);
  179. }
  180. // Show in rss or proprietary format?
  181. $xml_format = isset($_GET['type']) && in_array($_GET['type'], array('smf', 'rss', 'rss2', 'atom', 'rdf', 'webslice')) ? $_GET['type'] : 'smf';
  182. // !!! Birthdays?
  183. // List all the different types of data they can pull.
  184. $subActions = array(
  185. 'recent' => array('getXmlRecent', 'recent-post'),
  186. 'news' => array('getXmlNews', 'article'),
  187. 'members' => array('getXmlMembers', 'member'),
  188. 'profile' => array('getXmlProfile', null),
  189. );
  190. if (empty($_GET['sa']) || !isset($subActions[$_GET['sa']]))
  191. $_GET['sa'] = 'recent';
  192. //!!! Temp - webslices doesn't do everything yet.
  193. if ($xml_format == 'webslice' && $_GET['sa'] != 'recent')
  194. $xml_format = 'rss2';
  195. // If this is webslices we kinda cheat - we allow a template that we call direct for the HTML, and we override the CDATA.
  196. elseif ($xml_format == 'webslice')
  197. {
  198. $context['user'] += $user_info;
  199. $cdata_override = true;
  200. loadTemplate('Xml');
  201. }
  202. // We only want some information, not all of it.
  203. $cachekey = array($xml_format, $_GET['action'], $_GET['limit'], $_GET['sa']);
  204. foreach (array('board', 'boards', 'c') as $var)
  205. if (isset($_REQUEST[$var]))
  206. $cachekey[] = $_REQUEST[$var];
  207. $cachekey = md5(serialize($cachekey) . (!empty($query_this_board) ? $query_this_board : ''));
  208. // Get the associative array representing the xml.
  209. if ($user_info['is_guest'] && !empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 3)
  210. $xml = cache_get_data('xmlfeed-' . $xml_format . ':' . $cachekey, 240);
  211. if (empty($xml))
  212. {
  213. $xml = $subActions[$_GET['sa']][0]($xml_format);
  214. if ($user_info['is_guest'] && !empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 3)
  215. cache_put_data('xmlfeed-' . $xml_format . ':' . $cachekey, $xml, 240);
  216. }
  217. $feed_title = htmlspecialchars(strip_tags($context['forum_name'])) . (isset($feed_title) ? $feed_title : '');
  218. // This is an xml file....
  219. ob_end_clean();
  220. if (!empty($modSettings['enableCompressedOutput']))
  221. @ob_start('ob_gzhandler');
  222. else
  223. ob_start();
  224. if ($xml_format == 'smf' || isset($_REQUEST['debug']))
  225. header('Content-Type: text/xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set']));
  226. elseif ($xml_format == 'rss' || $xml_format == 'rss2' || $xml_format == 'webslice')
  227. header('Content-Type: application/rss+xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set']));
  228. elseif ($xml_format == 'atom')
  229. header('Content-Type: application/atom+xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set']));
  230. elseif ($xml_format == 'rdf')
  231. header('Content-Type: ' . ($context['browser']['is_ie'] ? 'text/xml' : 'application/rdf+xml') . '; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set']));
  232. // First, output the xml header.
  233. echo '<?xml version="1.0" encoding="', $context['character_set'], '"?' . '>';
  234. // Are we outputting an rss feed or one with more information?
  235. if ($xml_format == 'rss' || $xml_format == 'rss2')
  236. {
  237. // Start with an RSS 2.0 header.
  238. echo '
  239. <rss version=', $xml_format == 'rss2' ? '"2.0"' : '"0.92"', ' xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">
  240. <channel>
  241. <title>', $feed_title, '</title>
  242. <link>', $scripturl, '</link>
  243. <description><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></description>';
  244. // Output all of the associative array, start indenting with 2 tabs, and name everything "item".
  245. dumpTags($xml, 2, 'item', $xml_format);
  246. // Output the footer of the xml.
  247. echo '
  248. </channel>
  249. </rss>';
  250. }
  251. elseif ($xml_format == 'webslice')
  252. {
  253. $context['recent_posts_data'] = $xml;
  254. // This always has RSS 2
  255. echo '
  256. <rss version="2.0" xmlns:mon="http://www.microsoft.com/schemas/rss/monitoring/2007" xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">
  257. <channel>
  258. <title>', $feed_title, ' - ', $txt['recent_posts'], '</title>
  259. <link>', $scripturl, '?action=recent</link>
  260. <description><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></description>
  261. <item>
  262. <title>', $feed_title, ' - ', $txt['recent_posts'], '</title>
  263. <link>', $scripturl, '?action=recent</link>
  264. <description><![CDATA[
  265. ', template_webslice_header_above(), '
  266. ', template_webslice_recent_posts(), '
  267. ', template_webslice_header_below(), '
  268. ]]></description>
  269. </item>
  270. </channel>
  271. </rss>';
  272. }
  273. elseif ($xml_format == 'atom')
  274. {
  275. echo '
  276. <feed xmlns="http://www.w3.org/2005/Atom">
  277. <title>', $feed_title, '</title>
  278. <link rel="alternate" type="text/html" href="', $scripturl, '" />
  279. <modified>', gmstrftime('%Y-%m-%dT%H:%M:%SZ'), '</modified>
  280. <tagline><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></tagline>
  281. <generator uri="http://www.simplemachines.org" version="', strtr($forum_version, array('SMF' => '')), '">SMF</generator>
  282. <author>
  283. <name>', strip_tags($context['forum_name']), '</name>
  284. </author>';
  285. dumpTags($xml, 2, 'entry', $xml_format);
  286. echo '
  287. </feed>';
  288. }
  289. elseif ($xml_format == 'rdf')
  290. {
  291. echo '
  292. <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://purl.org/rss/1.0/">
  293. <channel rdf:about="', $scripturl, '">
  294. <title>', $feed_title, '</title>
  295. <link>', $scripturl, '</link>
  296. <description><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></description>
  297. <items>
  298. <rdf:Seq>';
  299. foreach ($xml as $item)
  300. echo '
  301. <rdf:li rdf:resource="', $item['link'], '" />';
  302. echo '
  303. </rdf:Seq>
  304. </items>
  305. </channel>
  306. ';
  307. dumpTags($xml, 1, 'item', $xml_format);
  308. echo '
  309. </rdf:RDF>';
  310. }
  311. // Otherwise, we're using our proprietary formats - they give more data, though.
  312. else
  313. {
  314. echo '
  315. <smf:xml-feed xmlns:smf="http://www.simplemachines.org/" xmlns="http://www.simplemachines.org/xml/', $_GET['sa'], '" xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">';
  316. // Dump out that associative array. Indent properly.... and use the right names for the base elements.
  317. dumpTags($xml, 1, $subActions[$_GET['sa']][1], $xml_format);
  318. echo '
  319. </smf:xml-feed>';
  320. }
  321. obExit(false);
  322. }
  323. function fix_possible_url($val)
  324. {
  325. global $modSettings, $context, $scripturl;
  326. if (substr($val, 0, strlen($scripturl)) != $scripturl)
  327. return $val;
  328. if (isset($modSettings['integrate_fix_url']) && function_exists($modSettings['integrate_fix_url']))
  329. $val = call_user_func($modSettings['integrate_fix_url'], $val);
  330. if (empty($modSettings['queryless_urls']) || ($context['server']['is_cgi'] && @ini_get('cgi.fix_pathinfo') == 0 && @get_cfg_var('cgi.fix_pathinfo') == 0) || (!$context['server']['is_apache'] && !$context['server']['is_lighttpd']))
  331. return $val;
  332. $val = preg_replace('/^' . preg_quote($scripturl, '/') . '\?((?:board|topic)=[^#"]+)(#[^"]*)?$/e', '\'\' . $scripturl . \'/\' . strtr(\'$1\', \'&;=\', \'//,\') . \'.html$2\'', $val);
  333. return $val;
  334. }
  335. function cdata_parse($data, $ns = '')
  336. {
  337. global $smcFunc, $cdata_override;
  338. // Are we not doing it?
  339. if (!empty($cdata_override))
  340. return $data;
  341. $cdata = '<![CDATA[';
  342. for ($pos = 0, $n = $smcFunc['strlen']($data); $pos < $n; null)
  343. {
  344. $positions = array(
  345. $smcFunc['strpos']($data, '&', $pos),
  346. $smcFunc['strpos']($data, ']', $pos),
  347. );
  348. if ($ns != '')
  349. $positions[] = $smcFunc['strpos']($data, '<', $pos);
  350. foreach ($positions as $k => $dummy)
  351. {
  352. if ($dummy === false)
  353. unset($positions[$k]);
  354. }
  355. $old = $pos;
  356. $pos = empty($positions) ? $n : min($positions);
  357. if ($pos - $old > 0)
  358. $cdata .= $smcFunc['substr']($data, $old, $pos - $old);
  359. if ($pos >= $n)
  360. break;
  361. if ($smcFunc['substr']($data, $pos, 1) == '<')
  362. {
  363. $pos2 = $smcFunc['strpos']($data, '>', $pos);
  364. if ($pos2 === false)
  365. $pos2 = $n;
  366. if ($smcFunc['substr']($data, $pos + 1, 1) == '/')
  367. $cdata .= ']]></' . $ns . ':' . $smcFunc['substr']($data, $pos + 2, $pos2 - $pos - 1) . '<![CDATA[';
  368. else
  369. $cdata .= ']]><' . $ns . ':' . $smcFunc['substr']($data, $pos + 1, $pos2 - $pos) . '<![CDATA[';
  370. $pos = $pos2 + 1;
  371. }
  372. elseif ($smcFunc['substr']($data, $pos, 1) == ']')
  373. {
  374. $cdata .= ']]>&#093;<![CDATA[';
  375. $pos++;
  376. }
  377. elseif ($smcFunc['substr']($data, $pos, 1) == '&')
  378. {
  379. $pos2 = $smcFunc['strpos']($data, ';', $pos);
  380. if ($pos2 === false)
  381. $pos2 = $n;
  382. $ent = $smcFunc['substr']($data, $pos + 1, $pos2 - $pos - 1);
  383. if ($smcFunc['substr']($data, $pos + 1, 1) == '#')
  384. $cdata .= ']]>' . $smcFunc['substr']($data, $pos, $pos2 - $pos + 1) . '<![CDATA[';
  385. elseif (in_array($ent, array('amp', 'lt', 'gt', 'quot')))
  386. $cdata .= ']]>' . $smcFunc['substr']($data, $pos, $pos2 - $pos + 1) . '<![CDATA[';
  387. // !!! ??
  388. $pos = $pos2 + 1;
  389. }
  390. }
  391. $cdata .= ']]>';
  392. return strtr($cdata, array('<![CDATA[]]>' => ''));
  393. }
  394. function dumpTags($data, $i, $tag = null, $xml_format = '')
  395. {
  396. global $modSettings, $context, $scripturl;
  397. // For every array in the data...
  398. foreach ($data as $key => $val)
  399. {
  400. // Skip it, it's been set to null.
  401. if ($val === null)
  402. continue;
  403. // If a tag was passed, use it instead of the key.
  404. $key = isset($tag) ? $tag : $key;
  405. // First let's indent!
  406. echo "\n", str_repeat("\t", $i);
  407. // Grr, I hate kludges... almost worth doing it properly, here, but not quite.
  408. if ($xml_format == 'atom' && $key == 'link')
  409. {
  410. echo '<link rel="alternate" type="text/html" href="', fix_possible_url($val), '" />';
  411. continue;
  412. }
  413. // If it's empty/0/nothing simply output an empty tag.
  414. if ($val == '')
  415. echo '<', $key, ' />';
  416. else
  417. {
  418. // Beginning tag.
  419. if ($xml_format == 'rdf' && $key == 'item' && isset($val['link']))
  420. {
  421. echo '<', $key, ' rdf:about="', fix_possible_url($val['link']), '">';
  422. echo "\n", str_repeat("\t", $i + 1);
  423. echo '<dc:format>text/html</dc:format>';
  424. }
  425. elseif ($xml_format == 'atom' && $key == 'summary')
  426. echo '<', $key, ' type="html">';
  427. else
  428. echo '<', $key, '>';
  429. if (is_array($val))
  430. {
  431. // An array. Dump it, and then indent the tag.
  432. dumpTags($val, $i + 1, null, $xml_format);
  433. echo "\n", str_repeat("\t", $i), '</', $key, '>';
  434. }
  435. // A string with returns in it.... show this as a multiline element.
  436. elseif (strpos($val, "\n") !== false || strpos($val, '<br />') !== false)
  437. echo "\n", fix_possible_url($val), "\n", str_repeat("\t", $i), '</', $key, '>';
  438. // A simple string.
  439. else
  440. echo fix_possible_url($val), '</', $key, '>';
  441. }
  442. }
  443. }
  444. function getXmlMembers($xml_format)
  445. {
  446. global $scripturl, $smcFunc;
  447. // Find the most recent members.
  448. $request = $smcFunc['db_query']('', '
  449. SELECT id_member, member_name, real_name, date_registered, last_login
  450. FROM {db_prefix}members
  451. ORDER BY id_member DESC
  452. LIMIT {int:limit}',
  453. array(
  454. 'limit' => $_GET['limit'],
  455. )
  456. );
  457. $data = array();
  458. while ($row = $smcFunc['db_fetch_assoc']($request))
  459. {
  460. // Make the data look rss-ish.
  461. if ($xml_format == 'rss' || $xml_format == 'rss2')
  462. $data[] = array(
  463. 'title' => cdata_parse($row['real_name']),
  464. 'link' => $scripturl . '?action=profile;u=' . $row['id_member'],
  465. 'comments' => $scripturl . '?action=pm;sa=send;u=' . $row['id_member'],
  466. 'pubDate' => gmdate('D, d M Y H:i:s \G\M\T', $row['date_registered']),
  467. 'guid' => $scripturl . '?action=profile;u=' . $row['id_member'],
  468. );
  469. elseif ($xml_format == 'rdf')
  470. $data[] = array(
  471. 'title' => cdata_parse($row['real_name']),
  472. 'link' => $scripturl . '?action=profile;u=' . $row['id_member'],
  473. );
  474. elseif ($xml_format == 'atom')
  475. $data[] = array(
  476. 'title' => cdata_parse($row['real_name']),
  477. 'link' => $scripturl . '?action=profile;u=' . $row['id_member'],
  478. 'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['date_registered']),
  479. 'updated' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['last_login']),
  480. 'id' => $scripturl . '?action=profile;u=' . $row['id_member'],
  481. );
  482. // More logical format for the data, but harder to apply.
  483. else
  484. $data[] = array(
  485. 'name' => cdata_parse($row['real_name']),
  486. 'time' => htmlspecialchars(strip_tags(timeformat($row['date_registered']))),
  487. 'id' => $row['id_member'],
  488. 'link' => $scripturl . '?action=profile;u=' . $row['id_member']
  489. );
  490. }
  491. $smcFunc['db_free_result']($request);
  492. return $data;
  493. }
  494. function getXmlNews($xml_format)
  495. {
  496. global $user_info, $scripturl, $modSettings, $board;
  497. global $query_this_board, $smcFunc, $settings, $context;
  498. /* Find the latest posts that:
  499. - are the first post in their topic.
  500. - are on an any board OR in a specified board.
  501. - can be seen by this user.
  502. - are actually the latest posts. */
  503. $request = $smcFunc['db_query']('', '
  504. SELECT
  505. m.smileys_enabled, m.poster_time, m.id_msg, m.subject, m.body, m.modified_time,
  506. m.icon, t.id_topic, t.id_board, t.num_replies,
  507. b.name AS bname,
  508. mem.hide_email, IFNULL(mem.id_member, 0) AS id_member,
  509. IFNULL(mem.email_address, m.poster_email) AS poster_email,
  510. IFNULL(mem.real_name, m.poster_name) AS poster_name
  511. FROM {db_prefix}topics AS t
  512. INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
  513. INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
  514. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  515. WHERE ' . $query_this_board . (empty($board) ? '' : '
  516. AND t.id_board = {int:current_board}') . ($modSettings['postmod_active'] ? '
  517. AND t.approved = {int:is_approved}' : '') . '
  518. ORDER BY t.id_first_msg DESC
  519. LIMIT {int:limit}',
  520. array(
  521. 'current_board' => $board,
  522. 'is_approved' => 1,
  523. 'limit' => $_GET['limit'],
  524. )
  525. );
  526. $data = array();
  527. while ($row = $smcFunc['db_fetch_assoc']($request))
  528. {
  529. // Limit the length of the message, if the option is set.
  530. if (!empty($modSettings['xmlnews_maxlen']) && $smcFunc['strlen'](str_replace('<br />', "\n", $row['body'])) > $modSettings['xmlnews_maxlen'])
  531. $row['body'] = strtr($smcFunc['substr'](str_replace('<br />', "\n", $row['body']), 0, $modSettings['xmlnews_maxlen'] - 3), array("\n" => '<br />')) . '...';
  532. $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
  533. censorText($row['body']);
  534. censorText($row['subject']);
  535. // Being news, this actually makes sense in rss format.
  536. if ($xml_format == 'rss' || $xml_format == 'rss2')
  537. $data[] = array(
  538. 'title' => cdata_parse($row['subject']),
  539. 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.0',
  540. 'description' => cdata_parse($row['body']),
  541. 'author' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['poster_email'] : null,
  542. 'comments' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.0',
  543. 'category' => '<![CDATA[' . $row['bname'] . ']]>',
  544. 'pubDate' => gmdate('D, d M Y H:i:s \G\M\T', $row['poster_time']),
  545. 'guid' => $scripturl . '?topic=' . $row['id_topic'] . '.0',
  546. );
  547. elseif ($xml_format == 'rdf')
  548. $data[] = array(
  549. 'title' => cdata_parse($row['subject']),
  550. 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.0',
  551. 'description' => cdata_parse($row['body']),
  552. );
  553. elseif ($xml_format == 'atom')
  554. $data[] = array(
  555. 'title' => cdata_parse($row['subject']),
  556. 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.0',
  557. 'summary' => cdata_parse($row['body']),
  558. 'category' => array('term' => $row['id_board'], 'label' => cdata_parse($row['bname'])),
  559. 'author' => array(
  560. 'name' => $row['poster_name'],
  561. 'email' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['poster_email'] : null,
  562. 'uri' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : '',
  563. ),
  564. 'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['poster_time']),
  565. 'modified' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', empty($row['modified_time']) ? $row['poster_time'] : $row['modified_time']),
  566. 'id' => $scripturl . '?topic=' . $row['id_topic'] . '.0',
  567. 'icon' => $settings['images_url'] . '/icons/' . $row['icon'] . '.gif',
  568. );
  569. // The biggest difference here is more information.
  570. else
  571. $data[] = array(
  572. 'time' => htmlspecialchars(strip_tags(timeformat($row['poster_time']))),
  573. 'id' => $row['id_topic'],
  574. 'subject' => cdata_parse($row['subject']),
  575. 'body' => cdata_parse($row['body']),
  576. 'poster' => array(
  577. 'name' => cdata_parse($row['poster_name']),
  578. 'id' => $row['id_member'],
  579. 'link' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : '',
  580. ),
  581. 'topic' => $row['id_topic'],
  582. 'board' => array(
  583. 'name' => cdata_parse($row['bname']),
  584. 'id' => $row['id_board'],
  585. 'link' => $scripturl . '?board=' . $row['id_board'] . '.0',
  586. ),
  587. 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.0',
  588. );
  589. }
  590. $smcFunc['db_free_result']($request);
  591. return $data;
  592. }
  593. function getXmlRecent($xml_format)
  594. {
  595. global $user_info, $scripturl, $modSettings, $board;
  596. global $query_this_board, $smcFunc, $settings, $context;
  597. $request = $smcFunc['db_query']('', '
  598. SELECT m.id_msg
  599. FROM {db_prefix}messages AS m
  600. INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
  601. WHERE ' . $query_this_board . (empty($board) ? '' : '
  602. AND m.id_board = {int:current_board}') . ($modSettings['postmod_active'] ? '
  603. AND m.approved = {int:is_approved}' : '') . '
  604. ORDER BY m.id_msg DESC
  605. LIMIT {int:limit}',
  606. array(
  607. 'limit' => $_GET['limit'],
  608. 'current_board' => $board,
  609. 'is_approved' => 1,
  610. )
  611. );
  612. $messages = array();
  613. while ($row = $smcFunc['db_fetch_assoc']($request))
  614. $messages[] = $row['id_msg'];
  615. $smcFunc['db_free_result']($request);
  616. if (empty($messages))
  617. return array();
  618. // Find the most recent posts this user can see.
  619. $request = $smcFunc['db_query']('', '
  620. SELECT
  621. m.smileys_enabled, m.poster_time, m.id_msg, m.subject, m.body, m.id_topic, t.id_board,
  622. b.name AS bname, t.num_replies, m.id_member, m.icon, mf.id_member AS id_first_member,
  623. IFNULL(mem.real_name, m.poster_name) AS poster_name, mf.subject AS first_subject,
  624. IFNULL(memf.real_name, mf.poster_name) AS first_poster_name, mem.hide_email,
  625. IFNULL(mem.email_address, m.poster_email) AS poster_email, m.modified_time
  626. FROM {db_prefix}messages AS m
  627. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
  628. INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
  629. INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
  630. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  631. LEFT JOIN {db_prefix}members AS memf ON (memf.id_member = mf.id_member)
  632. WHERE m.id_msg IN ({array_int:message_list})
  633. ' . (empty($board) ? '' : 'AND t.id_board = {int:current_board}') . '
  634. ORDER BY m.id_msg DESC
  635. LIMIT {int:limit}',
  636. array(
  637. 'limit' => $_GET['limit'],
  638. 'current_board' => $board,
  639. 'message_list' => $messages,
  640. )
  641. );
  642. $data = array();
  643. while ($row = $smcFunc['db_fetch_assoc']($request))
  644. {
  645. // Limit the length of the message, if the option is set.
  646. if (!empty($modSettings['xmlnews_maxlen']) && $smcFunc['strlen'](str_replace('<br />', "\n", $row['body'])) > $modSettings['xmlnews_maxlen'])
  647. $row['body'] = strtr($smcFunc['substr'](str_replace('<br />', "\n", $row['body']), 0, $modSettings['xmlnews_maxlen'] - 3), array("\n" => '<br />')) . '...';
  648. $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
  649. censorText($row['body']);
  650. censorText($row['subject']);
  651. // Doesn't work as well as news, but it kinda does..
  652. if ($xml_format == 'rss' || $xml_format == 'rss2')
  653. $data[] = array(
  654. 'title' => $row['subject'],
  655. 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'],
  656. 'description' => cdata_parse($row['body']),
  657. 'author' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['poster_email'] : null,
  658. 'category' => cdata_parse($row['bname']),
  659. 'comments' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.0',
  660. 'pubDate' => gmdate('D, d M Y H:i:s \G\M\T', $row['poster_time']),
  661. 'guid' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']
  662. );
  663. elseif ($xml_format == 'rdf')
  664. $data[] = array(
  665. 'title' => $row['subject'],
  666. 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'],
  667. 'description' => cdata_parse($row['body']),
  668. );
  669. elseif ($xml_format == 'atom')
  670. $data[] = array(
  671. 'title' => $row['subject'],
  672. 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'],
  673. 'summary' => cdata_parse($row['body']),
  674. 'category' => array(
  675. 'term' => $row['id_board'],
  676. 'label' => cdata_parse($row['bname'])
  677. ),
  678. 'author' => array(
  679. 'name' => $row['poster_name'],
  680. 'email' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['poster_email'] : null,
  681. 'uri' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : ''
  682. ),
  683. 'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['poster_time']),
  684. 'updated' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', empty($row['modified_time']) ? $row['poster_time'] : $row['modified_time']),
  685. 'id' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'],
  686. 'icon' => $settings['images_url'] . '/icons/' . $row['icon'] . '.gif',
  687. );
  688. // A lot of information here. Should be enough to please the rss-ers.
  689. else
  690. $data[] = array(
  691. 'time' => htmlspecialchars(strip_tags(timeformat($row['poster_time']))),
  692. 'id' => $row['id_msg'],
  693. 'subject' => cdata_parse($row['subject']),
  694. 'body' => cdata_parse($row['body']),
  695. 'starter' => array(
  696. 'name' => cdata_parse($row['first_poster_name']),
  697. 'id' => $row['id_first_member'],
  698. 'link' => !empty($row['id_first_member']) ? $scripturl . '?action=profile;u=' . $row['id_first_member'] : ''
  699. ),
  700. 'poster' => array(
  701. 'name' => cdata_parse($row['poster_name']),
  702. 'id' => $row['id_member'],
  703. 'link' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : ''
  704. ),
  705. 'topic' => array(
  706. 'subject' => cdata_parse($row['first_subject']),
  707. 'id' => $row['id_topic'],
  708. 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.new#new'
  709. ),
  710. 'board' => array(
  711. 'name' => cdata_parse($row['bname']),
  712. 'id' => $row['id_board'],
  713. 'link' => $scripturl . '?board=' . $row['id_board'] . '.0'
  714. ),
  715. 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']
  716. );
  717. }
  718. $smcFunc['db_free_result']($request);
  719. return $data;
  720. }
  721. function getXmlProfile($xml_format)
  722. {
  723. global $scripturl, $memberContext, $user_profile, $modSettings, $user_info;
  724. // You must input a valid user....
  725. if (empty($_GET['u']) || loadMemberData((int) $_GET['u']) === false)
  726. return array();
  727. // Make sure the id is a number and not "I like trying to hack the database".
  728. $_GET['u'] = (int) $_GET['u'];
  729. // Load the member's contextual information!
  730. if (!loadMemberContext($_GET['u']))
  731. return array();
  732. // Okay, I admit it, I'm lazy. Stupid $_GET['u'] is long and hard to type.
  733. $profile = &$memberContext[$_GET['u']];
  734. if ($xml_format == 'rss' || $xml_format == 'rss2')
  735. $data = array(array(
  736. 'title' => cdata_parse($profile['name']),
  737. 'link' => $scripturl . '?action=profile;u=' . $profile['id'],
  738. 'description' => cdata_parse(isset($profile['group']) ? $profile['group'] : $profile['post_group']),
  739. 'comments' => $scripturl . '?action=pm;sa=send;u=' . $profile['id'],
  740. 'pubDate' => gmdate('D, d M Y H:i:s \G\M\T', $user_profile[$profile['id']]['date_registered']),
  741. 'guid' => $scripturl . '?action=profile;u=' . $profile['id'],
  742. ));
  743. elseif ($xml_format == 'rdf')
  744. $data = array(array(
  745. 'title' => cdata_parse($profile['name']),
  746. 'link' => $scripturl . '?action=profile;u=' . $profile['id'],
  747. 'description' => cdata_parse(isset($profile['group']) ? $profile['group'] : $profile['post_group']),
  748. ));
  749. elseif ($xml_format == 'atom')
  750. $data[] = array(
  751. 'title' => cdata_parse($profile['name']),
  752. 'link' => $scripturl . '?action=profile;u=' . $profile['id'],
  753. 'summary' => cdata_parse(isset($profile['group']) ? $profile['group'] : $profile['post_group']),
  754. 'author' => array(
  755. 'name' => $profile['real_name'],
  756. 'email' => in_array(showEmailAddress(!empty($profile['hide_email']), $profile['id']), array('yes', 'yes_permission_override')) ? $profile['email'] : null,
  757. 'uri' => !empty($profile['website']) ? $profile['website']['url'] : ''
  758. ),
  759. 'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $user_profile[$profile['id']]['date_registered']),
  760. 'updated' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $user_profile[$profile['id']]['last_login']),
  761. 'id' => $scripturl . '?action=profile;u=' . $profile['id'],
  762. 'logo' => !empty($profile['avatar']) ? $profile['avatar']['url'] : '',
  763. );
  764. else
  765. {
  766. $data = array(
  767. 'username' => $user_info['is_admin'] || $user_info['id'] == $profile['id'] ? cdata_parse($profile['username']) : '',
  768. 'name' => cdata_parse($profile['name']),
  769. 'link' => $scripturl . '?action=profile;u=' . $profile['id'],
  770. 'posts' => $profile['posts'],
  771. 'post-group' => cdata_parse($profile['post_group']),
  772. 'language' => cdata_parse($profile['language']),
  773. 'last-login' => gmdate('D, d M Y H:i:s \G\M\T', $user_profile[$profile['id']]['last_login']),
  774. 'registered' => gmdate('D, d M Y H:i:s \G\M\T', $user_profile[$profile['id']]['date_registered'])
  775. );
  776. // Everything below here might not be set, and thus maybe shouldn't be displayed.
  777. if ($profile['gender']['name'] != '')
  778. $data['gender'] = cdata_parse($profile['gender']['name']);
  779. if ($profile['avatar']['name'] != '')
  780. $data['avatar'] = $profile['avatar']['url'];
  781. // If they are online, show an empty tag... no reason to put anything inside it.
  782. if ($profile['online']['is_online'])
  783. $data['online'] = '';
  784. if ($profile['signature'] != '')
  785. $data['signature'] = cdata_parse($profile['signature']);
  786. if ($profile['blurb'] != '')
  787. $data['blurb'] = cdata_parse($profile['blurb']);
  788. if ($profile['location'] != '')
  789. $data['location'] = cdata_parse($profile['location']);
  790. if ($profile['title'] != '')
  791. $data['title'] = cdata_parse($profile['title']);
  792. if (!empty($profile['icq']['name']) && !(!empty($modSettings['guest_hideContacts']) && $user_info['is_guest']))
  793. $data['icq'] = $profile['icq']['name'];
  794. if ($profile['aim']['name'] != '' && !(!empty($modSettings['guest_hideContacts']) && $user_info['is_guest']))
  795. $data['aim'] = $profile['aim']['name'];
  796. if ($profile['msn']['name'] != '' && !(!empty($modSettings['guest_hideContacts']) && $user_info['is_guest']))
  797. $data['msn'] = $profile['msn']['name'];
  798. if ($profile['yim']['name'] != '' && !(!empty($modSettings['guest_hideContacts']) && $user_info['is_guest']))
  799. $data['yim'] = $profile['yim']['name'];
  800. if ($profile['website']['title'] != '')
  801. $data['website'] = array(
  802. 'title' => cdata_parse($profile['website']['title']),
  803. 'link' => $profile['website']['url']
  804. );
  805. if ($profile['group'] != '')
  806. $data['postition'] = cdata_parse($profile['group']);
  807. if (!empty($modSettings['karmaMode']))
  808. $data['karma'] = array(
  809. 'good' => $profile['karma']['good'],
  810. 'bad' => $profile['karma']['bad']
  811. );
  812. if (in_array($profile['show_email'], array('yes', 'yes_permission_override')))
  813. $data['email'] = $profile['email'];
  814. if (!empty($profile['birth_date']) && substr($profile['birth_date'], 0, 4) != '0000')
  815. {
  816. list ($birth_year, $birth_month, $birth_day) = sscanf($profile['birth_date'], '%d-%d-%d');
  817. $datearray = getdate(forum_time());
  818. $data['age'] = $datearray['year'] - $birth_year - (($datearray['mon'] > $birth_month || ($datearray['mon'] == $birth_month && $datearray['mday'] >= $birth_day)) ? 0 : 1);
  819. }
  820. }
  821. // Save some memory.
  822. unset($profile, $memberContext[$_GET['u']]);
  823. return $data;
  824. }
  825. ?>