|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* This file contains the files necessary to display news as an XML feed. |
|
5
|
|
|
* |
|
6
|
|
|
* Simple Machines Forum (SMF) |
|
7
|
|
|
* |
|
8
|
|
|
* @package SMF |
|
9
|
|
|
* @author Simple Machines http://www.simplemachines.org |
|
10
|
|
|
* @copyright 2016 Simple Machines and individual contributors |
|
11
|
|
|
* @license http://www.simplemachines.org/about/smf/license.php BSD |
|
12
|
|
|
* |
|
13
|
|
|
* @version 2.1 Beta 3 |
|
14
|
|
|
*/ |
|
15
|
|
|
|
|
16
|
|
|
if (!defined('SMF')) |
|
17
|
|
|
die('No direct access...'); |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Outputs xml data representing recent information or a profile. |
|
21
|
|
|
* Can be passed 4 subactions which decide what is output: |
|
22
|
|
|
* 'recent' for recent posts, |
|
23
|
|
|
* 'news' for news topics, |
|
24
|
|
|
* 'members' for recently registered members, |
|
25
|
|
|
* 'profile' for a member's profile. |
|
26
|
|
|
* To display a member's profile, a user id has to be given. (;u=1) |
|
27
|
|
|
* Outputs an rss feed instead of a proprietary one if the 'type' $_GET |
|
28
|
|
|
* parameter is 'rss' or 'rss2'. |
|
29
|
|
|
* Accessed via ?action=.xml. |
|
30
|
|
|
* Does not use any templates, sub templates, or template layers. |
|
31
|
|
|
* |
|
32
|
|
|
* @uses Stats language file. |
|
33
|
|
|
*/ |
|
34
|
|
|
function ShowXmlFeed() |
|
35
|
|
|
{ |
|
36
|
|
|
global $board, $board_info, $context, $scripturl, $boardurl, $txt, $modSettings, $user_info; |
|
37
|
|
|
global $query_this_board, $smcFunc, $forum_version; |
|
38
|
|
|
|
|
39
|
|
|
// If it's not enabled, die. |
|
40
|
|
|
if (empty($modSettings['xmlnews_enable'])) |
|
41
|
|
|
obExit(false); |
|
42
|
|
|
|
|
43
|
|
|
loadLanguage('Stats'); |
|
44
|
|
|
|
|
45
|
|
|
// Default to latest 5. No more than 255, please. |
|
46
|
|
|
$_GET['limit'] = empty($_GET['limit']) || (int) $_GET['limit'] < 1 ? 5 : min((int) $_GET['limit'], 255); |
|
47
|
|
|
|
|
48
|
|
|
// Handle the cases where a board, boards, or category is asked for. |
|
49
|
|
|
$query_this_board = 1; |
|
50
|
|
|
$context['optimize_msg'] = array( |
|
51
|
|
|
'highest' => 'm.id_msg <= b.id_last_msg', |
|
52
|
|
|
); |
|
53
|
|
|
if (!empty($_REQUEST['c']) && empty($board)) |
|
54
|
|
|
{ |
|
55
|
|
|
$_REQUEST['c'] = explode(',', $_REQUEST['c']); |
|
56
|
|
|
foreach ($_REQUEST['c'] as $i => $c) |
|
57
|
|
|
$_REQUEST['c'][$i] = (int) $c; |
|
58
|
|
|
|
|
59
|
|
View Code Duplication |
if (count($_REQUEST['c']) == 1) |
|
|
|
|
|
|
60
|
|
|
{ |
|
61
|
|
|
$request = $smcFunc['db_query']('', ' |
|
62
|
|
|
SELECT name |
|
63
|
|
|
FROM {db_prefix}categories |
|
64
|
|
|
WHERE id_cat = {int:current_category}', |
|
65
|
|
|
array( |
|
66
|
|
|
'current_category' => (int) $_REQUEST['c'][0], |
|
67
|
|
|
) |
|
68
|
|
|
); |
|
69
|
|
|
list ($feed_title) = $smcFunc['db_fetch_row']($request); |
|
70
|
|
|
$smcFunc['db_free_result']($request); |
|
71
|
|
|
|
|
72
|
|
|
$feed_title = ' - ' . strip_tags($feed_title); |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
$request = $smcFunc['db_query']('', ' |
|
76
|
|
|
SELECT b.id_board, b.num_posts |
|
77
|
|
|
FROM {db_prefix}boards AS b |
|
78
|
|
|
WHERE b.id_cat IN ({array_int:current_category_list}) |
|
79
|
|
|
AND {query_see_board}', |
|
80
|
|
|
array( |
|
81
|
|
|
'current_category_list' => $_REQUEST['c'], |
|
82
|
|
|
) |
|
83
|
|
|
); |
|
84
|
|
|
$total_cat_posts = 0; |
|
85
|
|
|
$boards = array(); |
|
86
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
87
|
|
|
{ |
|
88
|
|
|
$boards[] = $row['id_board']; |
|
89
|
|
|
$total_cat_posts += $row['num_posts']; |
|
90
|
|
|
} |
|
91
|
|
|
$smcFunc['db_free_result']($request); |
|
92
|
|
|
|
|
93
|
|
|
if (!empty($boards)) |
|
94
|
|
|
$query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')'; |
|
95
|
|
|
|
|
96
|
|
|
// Try to limit the number of messages we look through. |
|
97
|
|
View Code Duplication |
if ($total_cat_posts > 100 && $total_cat_posts > $modSettings['totalMessages'] / 15) |
|
|
|
|
|
|
98
|
|
|
$context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 400 - $_GET['limit'] * 5); |
|
99
|
|
|
} |
|
100
|
|
|
elseif (!empty($_REQUEST['boards'])) |
|
101
|
|
|
{ |
|
102
|
|
|
$_REQUEST['boards'] = explode(',', $_REQUEST['boards']); |
|
103
|
|
|
foreach ($_REQUEST['boards'] as $i => $b) |
|
104
|
|
|
$_REQUEST['boards'][$i] = (int) $b; |
|
105
|
|
|
|
|
106
|
|
|
$request = $smcFunc['db_query']('', ' |
|
107
|
|
|
SELECT b.id_board, b.num_posts, b.name |
|
108
|
|
|
FROM {db_prefix}boards AS b |
|
109
|
|
|
WHERE b.id_board IN ({array_int:board_list}) |
|
110
|
|
|
AND {query_see_board} |
|
111
|
|
|
LIMIT {int:limit}', |
|
112
|
|
|
array( |
|
113
|
|
|
'board_list' => $_REQUEST['boards'], |
|
114
|
|
|
'limit' => count($_REQUEST['boards']), |
|
115
|
|
|
) |
|
116
|
|
|
); |
|
117
|
|
|
|
|
118
|
|
|
// Either the board specified doesn't exist or you have no access. |
|
119
|
|
|
$num_boards = $smcFunc['db_num_rows']($request); |
|
120
|
|
|
if ($num_boards == 0) |
|
121
|
|
|
fatal_lang_error('no_board'); |
|
122
|
|
|
|
|
123
|
|
|
$total_posts = 0; |
|
124
|
|
|
$boards = array(); |
|
125
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
126
|
|
|
{ |
|
127
|
|
|
if ($num_boards == 1) |
|
128
|
|
|
$feed_title = ' - ' . strip_tags($row['name']); |
|
129
|
|
|
|
|
130
|
|
|
$boards[] = $row['id_board']; |
|
131
|
|
|
$total_posts += $row['num_posts']; |
|
132
|
|
|
} |
|
133
|
|
|
$smcFunc['db_free_result']($request); |
|
134
|
|
|
|
|
135
|
|
|
if (!empty($boards)) |
|
136
|
|
|
$query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')'; |
|
137
|
|
|
|
|
138
|
|
|
// The more boards, the more we're going to look through... |
|
139
|
|
View Code Duplication |
if ($total_posts > 100 && $total_posts > $modSettings['totalMessages'] / 12) |
|
|
|
|
|
|
140
|
|
|
$context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 500 - $_GET['limit'] * 5); |
|
141
|
|
|
} |
|
142
|
|
|
elseif (!empty($board)) |
|
143
|
|
|
{ |
|
144
|
|
|
$request = $smcFunc['db_query']('', ' |
|
145
|
|
|
SELECT num_posts |
|
146
|
|
|
FROM {db_prefix}boards |
|
147
|
|
|
WHERE id_board = {int:current_board} |
|
148
|
|
|
LIMIT 1', |
|
149
|
|
|
array( |
|
150
|
|
|
'current_board' => $board, |
|
151
|
|
|
) |
|
152
|
|
|
); |
|
153
|
|
|
list ($total_posts) = $smcFunc['db_fetch_row']($request); |
|
154
|
|
|
$smcFunc['db_free_result']($request); |
|
155
|
|
|
|
|
156
|
|
|
$feed_title = ' - ' . strip_tags($board_info['name']); |
|
157
|
|
|
|
|
158
|
|
|
$query_this_board = 'b.id_board = ' . $board; |
|
159
|
|
|
|
|
160
|
|
|
// Try to look through just a few messages, if at all possible. |
|
161
|
|
View Code Duplication |
if ($total_posts > 80 && $total_posts > $modSettings['totalMessages'] / 10) |
|
|
|
|
|
|
162
|
|
|
$context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 600 - $_GET['limit'] * 5); |
|
163
|
|
|
} |
|
164
|
|
|
else |
|
165
|
|
|
{ |
|
166
|
|
|
$query_this_board = '{query_see_board}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' |
|
167
|
|
|
AND b.id_board != ' . $modSettings['recycle_board'] : ''); |
|
168
|
|
|
$context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 100 - $_GET['limit'] * 5); |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
// Show in rss or proprietary format? |
|
172
|
|
|
$xml_format = isset($_GET['type']) && in_array($_GET['type'], array('smf', 'rss', 'rss2', 'atom', 'rdf')) ? $_GET['type'] : 'smf'; |
|
173
|
|
|
|
|
174
|
|
|
// @todo Birthdays? |
|
175
|
|
|
|
|
176
|
|
|
// List all the different types of data they can pull. |
|
177
|
|
|
$subActions = array( |
|
178
|
|
|
'recent' => array('getXmlRecent', 'recent-post'), |
|
179
|
|
|
'news' => array('getXmlNews', 'article'), |
|
180
|
|
|
'members' => array('getXmlMembers', 'member'), |
|
181
|
|
|
'profile' => array('getXmlProfile', null), |
|
182
|
|
|
); |
|
183
|
|
|
|
|
184
|
|
|
// Easy adding of sub actions |
|
185
|
|
|
call_integration_hook('integrate_xmlfeeds', array(&$subActions)); |
|
186
|
|
|
|
|
187
|
|
|
if (empty($_GET['sa']) || !isset($subActions[$_GET['sa']])) |
|
188
|
|
|
$_GET['sa'] = 'recent'; |
|
189
|
|
|
|
|
190
|
|
|
// We only want some information, not all of it. |
|
191
|
|
|
$cachekey = array($xml_format, $_GET['action'], $_GET['limit'], $_GET['sa']); |
|
192
|
|
|
foreach (array('board', 'boards', 'c') as $var) |
|
193
|
|
|
if (isset($_REQUEST[$var])) |
|
194
|
|
|
$cachekey[] = $_REQUEST[$var]; |
|
195
|
|
|
$cachekey = md5(json_encode($cachekey) . (!empty($query_this_board) ? $query_this_board : '')); |
|
196
|
|
|
$cache_t = microtime(); |
|
197
|
|
|
|
|
198
|
|
|
// Get the associative array representing the xml. |
|
199
|
|
|
if (!empty($modSettings['cache_enable']) && (!$user_info['is_guest'] || $modSettings['cache_enable'] >= 3)) |
|
200
|
|
|
$xml = cache_get_data('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, 240); |
|
201
|
|
|
if (empty($xml)) |
|
202
|
|
|
{ |
|
203
|
|
|
$call = call_helper($subActions[$_GET['sa']][0], true); |
|
204
|
|
|
|
|
205
|
|
|
if (!empty($call)) |
|
206
|
|
|
$xml = call_user_func($call, $xml_format); |
|
207
|
|
|
|
|
208
|
|
|
if (!empty($modSettings['cache_enable']) && (($user_info['is_guest'] && $modSettings['cache_enable'] >= 3) |
|
209
|
|
|
|| (!$user_info['is_guest'] && (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $cache_t)) > 0.2)))) |
|
210
|
|
|
cache_put_data('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, $xml, 240); |
|
|
|
|
|
|
211
|
|
|
} |
|
212
|
|
|
|
|
213
|
|
|
$feed_title = $smcFunc['htmlspecialchars'](strip_tags($context['forum_name'])) . (isset($feed_title) ? $feed_title : ''); |
|
214
|
|
|
|
|
215
|
|
|
// If mods want to do somthing with this feed, let them do that now. |
|
216
|
|
|
// Provide the feed's data, title, format, and content type. |
|
217
|
|
|
call_integration_hook('integrate_xml_data', array(&$xml, &$feed_title, $xml_format, $_GET['sa'])); |
|
218
|
|
|
|
|
219
|
|
|
// This is an xml file.... |
|
220
|
|
|
ob_end_clean(); |
|
221
|
|
|
if (!empty($modSettings['enableCompressedOutput'])) |
|
222
|
|
|
@ob_start('ob_gzhandler'); |
|
|
|
|
|
|
223
|
|
|
else |
|
224
|
|
|
ob_start(); |
|
225
|
|
|
|
|
226
|
|
|
if ($xml_format == 'smf' || isset($_REQUEST['debug'])) |
|
227
|
|
|
header('Content-Type: text/xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set'])); |
|
228
|
|
View Code Duplication |
elseif ($xml_format == 'rss' || $xml_format == 'rss2') |
|
|
|
|
|
|
229
|
|
|
header('Content-Type: application/rss+xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set'])); |
|
230
|
|
View Code Duplication |
elseif ($xml_format == 'atom') |
|
|
|
|
|
|
231
|
|
|
header('Content-Type: application/atom+xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set'])); |
|
232
|
|
|
elseif ($xml_format == 'rdf') |
|
233
|
|
|
header('Content-Type: ' . (isBrowser('ie') ? 'text/xml' : 'application/rdf+xml') . '; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set'])); |
|
234
|
|
|
|
|
235
|
|
|
// First, output the xml header. |
|
236
|
|
|
echo '<?xml version="1.0" encoding="', $context['character_set'], '"?' . '>'; |
|
237
|
|
|
|
|
238
|
|
|
// Are we outputting an rss feed or one with more information? |
|
239
|
|
|
if ($xml_format == 'rss' || $xml_format == 'rss2') |
|
240
|
|
|
{ |
|
241
|
|
|
// Start with an RSS 2.0 header. |
|
242
|
|
|
echo ' |
|
243
|
|
|
<rss version=', $xml_format == 'rss2' ? '"2.0" xmlns:atom="http://www.w3.org/2005/Atom"' : '"0.92"', ' xml:lang="', strtr($txt['lang_locale'], '_', '-'), '"> |
|
244
|
|
|
<channel> |
|
245
|
|
|
<title>', $feed_title, '</title> |
|
246
|
|
|
<link>', $scripturl, '</link> |
|
247
|
|
|
<description>', cdata_parse(strip_tags($txt['xml_rss_desc'])), '</description>'; |
|
248
|
|
|
|
|
249
|
|
|
// RSS2 calls for this. |
|
250
|
|
|
if ($xml_format == 'rss2') |
|
251
|
|
|
echo '<atom:link rel="self" type="application/rss+xml" href="', $scripturl, '?action=.xml', !empty($_GET['sa']) ? ';sa=' . $_GET['sa'] : '', ';type=rss2" />'; |
|
252
|
|
|
|
|
253
|
|
|
// Output all of the associative array, start indenting with 2 tabs, and name everything "item". |
|
254
|
|
|
dumpTags($xml, 2, 'item', $xml_format); |
|
255
|
|
|
|
|
256
|
|
|
// Output the footer of the xml. |
|
257
|
|
|
echo ' |
|
258
|
|
|
</channel> |
|
259
|
|
|
</rss>'; |
|
260
|
|
|
} |
|
261
|
|
|
elseif ($xml_format == 'atom') |
|
262
|
|
|
{ |
|
263
|
|
|
foreach ($_REQUEST as $var => $val) |
|
264
|
|
|
if (in_array($var, array('action', 'sa', 'type', 'board', 'boards', 'c', 'u', 'limit'))) |
|
265
|
|
|
$url_parts[] = $var . '=' . (is_array($_REQUEST[$var]) ? implode(',', $_REQUEST[$var]) : $_REQUEST[$var]); |
|
|
|
|
|
|
266
|
|
|
|
|
267
|
|
|
echo ' |
|
268
|
|
|
<feed xmlns="http://www.w3.org/2005/Atom"> |
|
269
|
|
|
<title>', $feed_title, '</title> |
|
270
|
|
|
<link rel="alternate" type="text/html" href="', $scripturl, '" /> |
|
271
|
|
|
<link rel="self" type="application/atom+xml" href="', $scripturl, '?', !empty($url_parts) ? implode(';', $url_parts) : '', '" /> |
|
272
|
|
|
<id>', $scripturl, '</id> |
|
273
|
|
|
<icon>', $boardurl, '/favicon.ico</icon> |
|
274
|
|
|
|
|
275
|
|
|
<updated>', gmstrftime('%Y-%m-%dT%H:%M:%SZ'), '</updated> |
|
276
|
|
|
<subtitle>', cdata_parse(strip_tags($txt['xml_rss_desc'])), '</subtitle> |
|
277
|
|
|
<generator uri="http://www.simplemachines.org" version="', strtr($forum_version, array('SMF' => '')), '">SMF</generator> |
|
278
|
|
|
<author> |
|
279
|
|
|
<name>', cdata_parse(strip_tags($context['forum_name'])), '</name> |
|
280
|
|
|
</author>'; |
|
281
|
|
|
|
|
282
|
|
|
dumpTags($xml, 2, 'entry', $xml_format); |
|
283
|
|
|
|
|
284
|
|
|
echo ' |
|
285
|
|
|
</feed>'; |
|
286
|
|
|
} |
|
287
|
|
|
elseif ($xml_format == 'rdf') |
|
288
|
|
|
{ |
|
289
|
|
|
echo ' |
|
290
|
|
|
<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/"> |
|
291
|
|
|
<channel rdf:about="', $scripturl, '"> |
|
292
|
|
|
<title>', $feed_title, '</title> |
|
293
|
|
|
<link>', $scripturl, '</link> |
|
294
|
|
|
<description>', cdata_parse(strip_tags($txt['xml_rss_desc'])), '</description> |
|
295
|
|
|
<items> |
|
296
|
|
|
<rdf:Seq>'; |
|
297
|
|
|
|
|
298
|
|
|
foreach ($xml as $item) |
|
299
|
|
|
echo ' |
|
300
|
|
|
<rdf:li rdf:resource="', $item['link'], '" />'; |
|
301
|
|
|
|
|
302
|
|
|
echo ' |
|
303
|
|
|
</rdf:Seq> |
|
304
|
|
|
</items> |
|
305
|
|
|
</channel> |
|
306
|
|
|
'; |
|
307
|
|
|
|
|
308
|
|
|
dumpTags($xml, 1, 'item', $xml_format); |
|
309
|
|
|
|
|
310
|
|
|
echo ' |
|
311
|
|
|
</rdf:RDF>'; |
|
312
|
|
|
} |
|
313
|
|
|
// Otherwise, we're using our proprietary formats - they give more data, though. |
|
314
|
|
|
else |
|
315
|
|
|
{ |
|
316
|
|
|
echo ' |
|
317
|
|
|
<smf:xml-feed xmlns:smf="http://www.simplemachines.org/" xmlns="http://www.simplemachines.org/xml/', $_GET['sa'], '" xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">'; |
|
318
|
|
|
|
|
319
|
|
|
// Dump out that associative array. Indent properly.... and use the right names for the base elements. |
|
320
|
|
|
dumpTags($xml, 1, $subActions[$_GET['sa']][1], $xml_format); |
|
321
|
|
|
|
|
322
|
|
|
echo ' |
|
323
|
|
|
</smf:xml-feed>'; |
|
324
|
|
|
} |
|
325
|
|
|
|
|
326
|
|
|
obExit(false); |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
|
|
/** |
|
330
|
|
|
* Called from dumpTags to convert data to xml |
|
331
|
|
|
* Finds urls for local site and sanitizes them |
|
332
|
|
|
* |
|
333
|
|
|
* @param string $val A string containing a possible URL |
|
334
|
|
|
* @return string $val The string with any possible URLs sanitized |
|
335
|
|
|
*/ |
|
336
|
|
|
function fix_possible_url($val) |
|
337
|
|
|
{ |
|
338
|
|
|
global $modSettings, $context, $scripturl; |
|
339
|
|
|
|
|
340
|
|
|
if (substr($val, 0, strlen($scripturl)) != $scripturl) |
|
341
|
|
|
return $val; |
|
342
|
|
|
|
|
343
|
|
|
call_integration_hook('integrate_fix_url', array(&$val)); |
|
344
|
|
|
|
|
345
|
|
|
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'])) |
|
346
|
|
|
return $val; |
|
347
|
|
|
|
|
348
|
|
|
$val = preg_replace_callback('~^' . preg_quote($scripturl, '/') . '\?((?:board|topic)=[^#"]+)(#[^"]*)?$~', function ($m) use ($scripturl) |
|
349
|
|
|
{ |
|
350
|
|
|
return $scripturl . '/' . strtr("$m[1]", '&;=', '//,') . '.html' . (isset($m[2]) ? $m[2] : ""); |
|
351
|
|
|
}, $val); |
|
352
|
|
|
return $val; |
|
353
|
|
|
} |
|
354
|
|
|
|
|
355
|
|
|
/** |
|
356
|
|
|
* Ensures supplied data is properly encapsulated in cdata xml tags |
|
357
|
|
|
* Called from getXmlProfile in News.php |
|
358
|
|
|
* |
|
359
|
|
|
* @param string $data XML data |
|
360
|
|
|
* @param string $ns |
|
361
|
|
|
* @return string The XML data enclosed in cdata tags |
|
362
|
|
|
*/ |
|
363
|
|
|
function cdata_parse($data, $ns = '') |
|
364
|
|
|
{ |
|
365
|
|
|
global $smcFunc; |
|
366
|
|
|
|
|
367
|
|
|
// Do we even need to do this? |
|
368
|
|
|
if (strpbrk($data, '<>&') == false) |
|
|
|
|
|
|
369
|
|
|
return $data; |
|
370
|
|
|
|
|
371
|
|
|
$cdata = '<; $pos < $n; null) |
|
374
|
|
|
{ |
|
375
|
|
|
$positions = array( |
|
376
|
|
|
$smcFunc['strpos']($data, '&', $pos), |
|
377
|
|
|
$smcFunc['strpos']($data, ']', $pos), |
|
378
|
|
|
); |
|
379
|
|
|
if ($ns != '') |
|
380
|
|
|
$positions[] = $smcFunc['strpos']($data, '<', $pos); |
|
381
|
|
|
foreach ($positions as $k => $dummy) |
|
382
|
|
|
{ |
|
383
|
|
|
if ($dummy === false) |
|
384
|
|
|
unset($positions[$k]); |
|
385
|
|
|
} |
|
386
|
|
|
|
|
387
|
|
|
$old = $pos; |
|
388
|
|
|
$pos = empty($positions) ? $n : min($positions); |
|
389
|
|
|
|
|
390
|
|
|
if ($pos - $old > 0) |
|
391
|
|
|
$cdata .= $smcFunc['substr']($data, $old, $pos - $old); |
|
392
|
|
|
if ($pos >= $n) |
|
393
|
|
|
break; |
|
394
|
|
|
|
|
395
|
|
|
if ($smcFunc['substr']($data, $pos, 1) == '<') |
|
396
|
|
|
{ |
|
397
|
|
|
$pos2 = $smcFunc['strpos']($data, '>', $pos); |
|
398
|
|
|
if ($pos2 === false) |
|
399
|
|
|
$pos2 = $n; |
|
400
|
|
|
if ($smcFunc['substr']($data, $pos + 1, 1) == '/') |
|
401
|
|
|
$cdata .= ']]></' . $ns . ':' . $smcFunc['substr']($data, $pos + 2, $pos2 - $pos - 1) . '<![CDATA['; |
|
402
|
|
|
else |
|
403
|
|
|
$cdata .= ']]><' . $ns . ':' . $smcFunc['substr']($data, $pos + 1, $pos2 - $pos) . '< == ']') |
|
407
|
|
|
{ |
|
408
|
|
|
$cdata .= ']]>]< == '&') |
|
412
|
|
|
{ |
|
413
|
|
|
$pos2 = $smcFunc['strpos']($data, ';', $pos); |
|
414
|
|
|
if ($pos2 === false) |
|
415
|
|
|
$pos2 = $n; |
|
416
|
|
|
$ent = $smcFunc['substr']($data, $pos + 1, $pos2 - $pos - 1); |
|
417
|
|
|
|
|
418
|
|
|
if ($smcFunc['substr']($data, $pos + 1, 1) == '#') |
|
419
|
|
|
$cdata .= ']]>' . $smcFunc['substr']($data, $pos, $pos2 - $pos + 1) . '<![CDATA['; |
|
420
|
|
|
elseif (in_array($ent, array('amp', 'lt', 'gt', 'quot'))) |
|
421
|
|
|
$cdata .= ']]>' . $smcFunc['substr']($data, $pos, $pos2 - $pos + 1) . '<![CDATA['; |
|
422
|
|
|
|
|
423
|
|
|
$pos = $pos2 + 1; |
|
424
|
|
|
} |
|
425
|
|
|
} |
|
426
|
|
|
|
|
427
|
|
|
$cdata .= ']]>'; |
|
428
|
|
|
|
|
429
|
|
|
return strtr($cdata, array('<![CDATA[]]>' => '')); |
|
430
|
|
|
} |
|
431
|
|
|
|
|
432
|
|
|
/** |
|
433
|
|
|
* Formats data retrieved in other functions into xml format. |
|
434
|
|
|
* Additionally formats data based on the specific format passed. |
|
435
|
|
|
* This function is recursively called to handle sub arrays of data. |
|
436
|
|
|
|
|
437
|
|
|
* @param array $data The array to output as xml data |
|
438
|
|
|
* @param int $i The amount of indentation to use. |
|
439
|
|
|
* @param null|string $tag If specified, it will be used instead of the keys of data. |
|
440
|
|
|
* @param string $xml_format The format to use ('atom', 'rss', 'rss2' or empty for plain XML) |
|
441
|
|
|
*/ |
|
442
|
|
|
function dumpTags($data, $i, $tag = null, $xml_format = '') |
|
443
|
|
|
{ |
|
444
|
|
|
// Wrap the values of these keys into CDATA tags |
|
445
|
|
|
$keysToCdata = array( |
|
446
|
|
|
'title', |
|
447
|
|
|
'name', |
|
448
|
|
|
'description', |
|
449
|
|
|
'summary', |
|
450
|
|
|
'subject', |
|
451
|
|
|
'body', |
|
452
|
|
|
'username', |
|
453
|
|
|
'signature', |
|
454
|
|
|
'position', |
|
455
|
|
|
'language', |
|
456
|
|
|
'gender', |
|
457
|
|
|
'blurb', |
|
458
|
|
|
); |
|
459
|
|
|
if ($xml_format != 'atom') |
|
460
|
|
|
$keysToCdata[] = 'category'; |
|
461
|
|
|
|
|
462
|
|
|
// For every array in the data... |
|
463
|
|
|
foreach ($data as $key => $val) |
|
464
|
|
|
{ |
|
465
|
|
|
// Skip it, it's been set to null. |
|
466
|
|
|
if ($val === null) |
|
467
|
|
|
continue; |
|
468
|
|
|
|
|
469
|
|
|
// If the value should maybe be CDATA, do that now. |
|
470
|
|
|
if (!is_array($val) && in_array($key, $keysToCdata)) |
|
471
|
|
|
$val = cdata_parse($val); |
|
472
|
|
|
|
|
473
|
|
|
// If a tag was passed, use it instead of the key. |
|
474
|
|
|
$key = isset($tag) ? $tag : $key; |
|
475
|
|
|
|
|
476
|
|
|
// First let's indent! |
|
477
|
|
|
echo "\n", str_repeat("\t", $i); |
|
478
|
|
|
|
|
479
|
|
|
// Grr, I hate kludges... almost worth doing it properly, here, but not quite. |
|
480
|
|
|
if ($xml_format == 'atom' && $key == 'link') |
|
481
|
|
|
{ |
|
482
|
|
|
echo '<link rel="alternate" type="text/html" href="', fix_possible_url($val), '" />'; |
|
483
|
|
|
continue; |
|
484
|
|
|
} |
|
485
|
|
|
|
|
486
|
|
|
// If it's empty/0/nothing simply output an empty tag. |
|
487
|
|
|
if ($val == '') |
|
488
|
|
|
echo '<', $key, ' />'; |
|
489
|
|
|
elseif ($xml_format == 'atom' && $key == 'category') |
|
490
|
|
|
echo '<', $key, ' term="', $val, '" />'; |
|
491
|
|
|
else |
|
492
|
|
|
{ |
|
493
|
|
|
// Beginning tag. |
|
494
|
|
|
if ($xml_format == 'rdf' && $key == 'item' && isset($val['link'])) |
|
495
|
|
|
{ |
|
496
|
|
|
echo '<', $key, ' rdf:about="', fix_possible_url($val['link']), '">'; |
|
497
|
|
|
echo "\n", str_repeat("\t", $i + 1); |
|
498
|
|
|
echo '<dc:format>text/html</dc:format>'; |
|
499
|
|
|
} |
|
500
|
|
|
elseif ($xml_format == 'atom' && $key == 'summary') |
|
501
|
|
|
echo '<', $key, ' type="html">'; |
|
502
|
|
|
else |
|
503
|
|
|
echo '<', $key, '>'; |
|
504
|
|
|
|
|
505
|
|
|
// The element's value. |
|
506
|
|
|
if (is_array($val)) |
|
507
|
|
|
{ |
|
508
|
|
|
// An array. Dump it, and then indent the tag. |
|
509
|
|
|
dumpTags($val, $i + 1, null, $xml_format); |
|
510
|
|
|
echo "\n", str_repeat("\t", $i); |
|
511
|
|
|
} |
|
512
|
|
|
// A string with returns in it.... show this as a multiline element. |
|
513
|
|
|
elseif (strpos($val, "\n") !== false || preg_match('~<br ?/?' . '>~', $val) !== false) |
|
514
|
|
|
echo "\n", fix_possible_url($val), "\n", str_repeat("\t", $i); |
|
515
|
|
|
// A simple string. |
|
516
|
|
|
else |
|
517
|
|
|
echo fix_possible_url($val); |
|
518
|
|
|
|
|
519
|
|
|
// Ending tag. |
|
520
|
|
|
echo '</', $key, '>'; |
|
521
|
|
|
} |
|
522
|
|
|
} |
|
523
|
|
|
} |
|
524
|
|
|
|
|
525
|
|
|
/** |
|
526
|
|
|
* Retrieve the list of members from database. |
|
527
|
|
|
* The array will be generated to match the format. |
|
528
|
|
|
* @todo get the list of members from Subs-Members. |
|
529
|
|
|
* |
|
530
|
|
|
* @param string $xml_format The format to use. Can be 'atom', 'rdf', 'rss', 'rss2' or 'xml' |
|
531
|
|
|
* @return array An array of arrays of feed items. Each array has keys corresponding to the appropriate tags for the specified format. |
|
532
|
|
|
*/ |
|
533
|
|
|
function getXmlMembers($xml_format) |
|
534
|
|
|
{ |
|
535
|
|
|
global $scripturl, $smcFunc; |
|
536
|
|
|
|
|
537
|
|
|
if (!allowedTo('view_mlist')) |
|
538
|
|
|
return array(); |
|
539
|
|
|
|
|
540
|
|
|
// Find the most recent members. |
|
541
|
|
|
$request = $smcFunc['db_query']('', ' |
|
542
|
|
|
SELECT id_member, member_name, real_name, date_registered, last_login |
|
543
|
|
|
FROM {db_prefix}members |
|
544
|
|
|
ORDER BY id_member DESC |
|
545
|
|
|
LIMIT {int:limit}', |
|
546
|
|
|
array( |
|
547
|
|
|
'limit' => $_GET['limit'], |
|
548
|
|
|
) |
|
549
|
|
|
); |
|
550
|
|
|
$data = array(); |
|
551
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
552
|
|
|
{ |
|
553
|
|
|
// Make the data look rss-ish. |
|
554
|
|
|
if ($xml_format == 'rss' || $xml_format == 'rss2') |
|
555
|
|
|
$data[] = array( |
|
556
|
|
|
'title' => $row['real_name'], |
|
557
|
|
|
'link' => $scripturl . '?action=profile;u=' . $row['id_member'], |
|
558
|
|
|
'comments' => $scripturl . '?action=pm;sa=send;u=' . $row['id_member'], |
|
559
|
|
|
'pubDate' => gmdate('D, d M Y H:i:s \G\M\T', $row['date_registered']), |
|
560
|
|
|
'guid' => $scripturl . '?action=profile;u=' . $row['id_member'], |
|
561
|
|
|
); |
|
562
|
|
|
elseif ($xml_format == 'rdf') |
|
563
|
|
|
$data[] = array( |
|
564
|
|
|
'title' => $row['real_name'], |
|
565
|
|
|
'link' => $scripturl . '?action=profile;u=' . $row['id_member'], |
|
566
|
|
|
); |
|
567
|
|
|
elseif ($xml_format == 'atom') |
|
568
|
|
|
$data[] = array( |
|
569
|
|
|
'title' => $row['real_name'], |
|
570
|
|
|
'link' => $scripturl . '?action=profile;u=' . $row['id_member'], |
|
571
|
|
|
'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['date_registered']), |
|
572
|
|
|
'updated' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['last_login']), |
|
573
|
|
|
'id' => $scripturl . '?action=profile;u=' . $row['id_member'], |
|
574
|
|
|
); |
|
575
|
|
|
// More logical format for the data, but harder to apply. |
|
576
|
|
|
else |
|
577
|
|
|
$data[] = array( |
|
578
|
|
|
'name' => $row['real_name'], |
|
579
|
|
|
'time' => $smcFunc['htmlspecialchars'](strip_tags(timeformat($row['date_registered']))), |
|
580
|
|
|
'id' => $row['id_member'], |
|
581
|
|
|
'link' => $scripturl . '?action=profile;u=' . $row['id_member'] |
|
582
|
|
|
); |
|
583
|
|
|
} |
|
584
|
|
|
$smcFunc['db_free_result']($request); |
|
585
|
|
|
|
|
586
|
|
|
return $data; |
|
587
|
|
|
} |
|
588
|
|
|
|
|
589
|
|
|
/** |
|
590
|
|
|
* Get the latest topics information from a specific board, |
|
591
|
|
|
* to display later. |
|
592
|
|
|
* The returned array will be generated to match the xmf_format. |
|
593
|
|
|
* @todo does not belong here |
|
594
|
|
|
* |
|
595
|
|
|
* @param $xml_format The XML format. Can be 'atom', 'rdf', 'rss', 'rss2' or 'xml'. |
|
596
|
|
|
* @return array An array of arrays of topic data for the feed. Each array has keys corresponding to the tags for the specified format. |
|
597
|
|
|
*/ |
|
598
|
|
|
function getXmlNews($xml_format) |
|
599
|
|
|
{ |
|
600
|
|
|
global $scripturl, $modSettings, $board, $user_info; |
|
601
|
|
|
global $query_this_board, $smcFunc, $context; |
|
602
|
|
|
|
|
603
|
|
|
/* Find the latest posts that: |
|
604
|
|
|
- are the first post in their topic. |
|
605
|
|
|
- are on an any board OR in a specified board. |
|
606
|
|
|
- can be seen by this user. |
|
607
|
|
|
- are actually the latest posts. */ |
|
608
|
|
|
|
|
609
|
|
|
$done = false; |
|
610
|
|
|
$loops = 0; |
|
611
|
|
|
while (!$done) |
|
612
|
|
|
{ |
|
613
|
|
|
$optimize_msg = implode(' AND ', $context['optimize_msg']); |
|
614
|
|
|
$request = $smcFunc['db_query']('', ' |
|
615
|
|
|
SELECT |
|
616
|
|
|
m.smileys_enabled, m.poster_time, m.id_msg, m.subject, m.body, m.modified_time, |
|
617
|
|
|
m.icon, t.id_topic, t.id_board, t.num_replies, |
|
618
|
|
|
b.name AS bname, |
|
619
|
|
|
COALESCE(mem.id_member, 0) AS id_member, |
|
620
|
|
|
COALESCE(mem.email_address, m.poster_email) AS poster_email, |
|
621
|
|
|
COALESCE(mem.real_name, m.poster_name) AS poster_name |
|
622
|
|
|
FROM {db_prefix}topics AS t |
|
623
|
|
|
INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) |
|
624
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
|
625
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
|
626
|
|
|
WHERE ' . $query_this_board . (empty($optimize_msg) ? '' : ' |
|
627
|
|
|
AND {raw:optimize_msg}') . (empty($board) ? '' : ' |
|
628
|
|
|
AND t.id_board = {int:current_board}') . ($modSettings['postmod_active'] ? ' |
|
629
|
|
|
AND t.approved = {int:is_approved}' : '') . ' |
|
630
|
|
|
ORDER BY t.id_first_msg DESC |
|
631
|
|
|
LIMIT {int:limit}', |
|
632
|
|
|
array( |
|
633
|
|
|
'current_board' => $board, |
|
634
|
|
|
'is_approved' => 1, |
|
635
|
|
|
'limit' => $_GET['limit'], |
|
636
|
|
|
'optimize_msg' => $optimize_msg, |
|
637
|
|
|
) |
|
638
|
|
|
); |
|
639
|
|
|
// If we don't have $_GET['limit'] results, try again with an unoptimized version covering all rows. |
|
640
|
|
|
if ($loops < 2 && $smcFunc['db_num_rows']($request) < $_GET['limit']) |
|
641
|
|
|
{ |
|
642
|
|
|
$smcFunc['db_free_result']($request); |
|
643
|
|
View Code Duplication |
if (empty($_REQUEST['boards']) && empty($board)) |
|
|
|
|
|
|
644
|
|
|
unset($context['optimize_msg']['lowest']); |
|
645
|
|
|
else |
|
646
|
|
|
$context['optimize_msg']['lowest'] = 'm.id_msg >= t.id_first_msg'; |
|
647
|
|
|
$context['optimize_msg']['highest'] = 'm.id_msg <= t.id_last_msg'; |
|
648
|
|
|
$loops++; |
|
649
|
|
|
} |
|
650
|
|
|
else |
|
651
|
|
|
$done = true; |
|
652
|
|
|
} |
|
653
|
|
|
$data = array(); |
|
654
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
|
|
|
|
|
655
|
|
|
{ |
|
656
|
|
|
// Limit the length of the message, if the option is set. |
|
657
|
|
View Code Duplication |
if (!empty($modSettings['xmlnews_maxlen']) && $smcFunc['strlen'](str_replace('<br>', "\n", $row['body'])) > $modSettings['xmlnews_maxlen']) |
|
|
|
|
|
|
658
|
|
|
$row['body'] = strtr($smcFunc['substr'](str_replace('<br>', "\n", $row['body']), 0, $modSettings['xmlnews_maxlen'] - 3), array("\n" => '<br>')) . '...'; |
|
659
|
|
|
|
|
660
|
|
|
$row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']); |
|
661
|
|
|
|
|
662
|
|
|
censorText($row['body']); |
|
663
|
|
|
censorText($row['subject']); |
|
664
|
|
|
|
|
665
|
|
|
// Being news, this actually makes sense in rss format. |
|
666
|
|
|
if ($xml_format == 'rss' || $xml_format == 'rss2') |
|
667
|
|
|
$data[] = array( |
|
668
|
|
|
'title' => $row['subject'], |
|
669
|
|
|
'link' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
|
670
|
|
|
'description' => $row['body'], |
|
671
|
|
|
'author' => (allowedTo('moderate_forum') || $row['id_member'] == $user_info['id']) ? $row['poster_email'] . ' ('.$row['poster_name'].')' : null, |
|
672
|
|
|
'comments' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.0', |
|
673
|
|
|
'category' => $row['bname'], |
|
674
|
|
|
'pubDate' => gmdate('D, d M Y H:i:s \G\M\T', $row['poster_time']), |
|
675
|
|
|
'guid' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
|
676
|
|
|
); |
|
677
|
|
|
elseif ($xml_format == 'rdf') |
|
678
|
|
|
$data[] = array( |
|
679
|
|
|
'title' => $row['subject'], |
|
680
|
|
|
'link' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
|
681
|
|
|
'description' => $row['body'], |
|
682
|
|
|
); |
|
683
|
|
|
elseif ($xml_format == 'atom') |
|
684
|
|
|
$data[] = array( |
|
685
|
|
|
'title' => $row['subject'], |
|
686
|
|
|
'link' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
|
687
|
|
|
'summary' => $row['body'], |
|
688
|
|
|
'category' => $row['bname'], |
|
689
|
|
|
'author' => array( |
|
690
|
|
|
'name' => $row['poster_name'], |
|
691
|
|
|
'email' => (allowedTo('moderate_forum') || $row['id_member'] == $user_info['id']) ? $row['poster_email'] : null, |
|
692
|
|
|
'uri' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : null, |
|
693
|
|
|
), |
|
694
|
|
|
'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['poster_time']), |
|
695
|
|
|
'updated' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', empty($row['modified_time']) ? $row['poster_time'] : $row['modified_time']), |
|
696
|
|
|
'id' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
|
697
|
|
|
); |
|
698
|
|
|
// The biggest difference here is more information. |
|
699
|
|
|
else |
|
700
|
|
|
$data[] = array( |
|
701
|
|
|
'time' => $smcFunc['htmlspecialchars'](strip_tags(timeformat($row['poster_time']))), |
|
702
|
|
|
'id' => $row['id_topic'], |
|
703
|
|
|
'subject' => $row['subject'], |
|
704
|
|
|
'body' => $row['body'], |
|
705
|
|
|
'poster' => array( |
|
706
|
|
|
'name' => $row['poster_name'], |
|
707
|
|
|
'id' => $row['id_member'], |
|
708
|
|
|
'link' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : '', |
|
709
|
|
|
), |
|
710
|
|
|
'topic' => $row['id_topic'], |
|
711
|
|
|
'board' => array( |
|
712
|
|
|
'name' => $row['bname'], |
|
713
|
|
|
'id' => $row['id_board'], |
|
714
|
|
|
'link' => $scripturl . '?board=' . $row['id_board'] . '.0', |
|
715
|
|
|
), |
|
716
|
|
|
'link' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
|
717
|
|
|
); |
|
718
|
|
|
} |
|
719
|
|
|
$smcFunc['db_free_result']($request); |
|
720
|
|
|
|
|
721
|
|
|
return $data; |
|
722
|
|
|
} |
|
723
|
|
|
|
|
724
|
|
|
/** |
|
725
|
|
|
* Get the recent topics to display. |
|
726
|
|
|
* The returned array will be generated to match the xml_format. |
|
727
|
|
|
* @todo does not belong here. |
|
728
|
|
|
* |
|
729
|
|
|
* @param string $xml_format The XML format. Can be 'atom', 'rdf', 'rss', 'rss2' or 'xml' |
|
730
|
|
|
* @return array An array of arrays containing data for the feed. Each array has keys corresponding to the appropriate tags for the specified format. |
|
731
|
|
|
*/ |
|
732
|
|
|
function getXmlRecent($xml_format) |
|
733
|
|
|
{ |
|
734
|
|
|
global $scripturl, $modSettings, $board; |
|
735
|
|
|
global $query_this_board, $smcFunc, $context, $user_info; |
|
736
|
|
|
|
|
737
|
|
|
$done = false; |
|
738
|
|
|
$loops = 0; |
|
739
|
|
|
while (!$done) |
|
740
|
|
|
{ |
|
741
|
|
|
$optimize_msg = implode(' AND ', $context['optimize_msg']); |
|
742
|
|
|
$request = $smcFunc['db_query']('', ' |
|
743
|
|
|
SELECT m.id_msg |
|
744
|
|
|
FROM {db_prefix}messages AS m |
|
745
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) |
|
746
|
|
|
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) |
|
747
|
|
|
WHERE ' . $query_this_board . (empty($optimize_msg) ? '' : ' |
|
748
|
|
|
AND {raw:optimize_msg}') . (empty($board) ? '' : ' |
|
749
|
|
|
AND m.id_board = {int:current_board}') . ($modSettings['postmod_active'] ? ' |
|
750
|
|
|
AND m.approved = {int:is_approved}' : '') . ' |
|
751
|
|
|
ORDER BY m.id_msg DESC |
|
752
|
|
|
LIMIT {int:limit}', |
|
753
|
|
|
array( |
|
754
|
|
|
'limit' => $_GET['limit'], |
|
755
|
|
|
'current_board' => $board, |
|
756
|
|
|
'is_approved' => 1, |
|
757
|
|
|
'optimize_msg' => $optimize_msg, |
|
758
|
|
|
) |
|
759
|
|
|
); |
|
760
|
|
|
// If we don't have $_GET['limit'] results, try again with an unoptimized version covering all rows. |
|
761
|
|
|
if ($loops < 2 && $smcFunc['db_num_rows']($request) < $_GET['limit']) |
|
762
|
|
|
{ |
|
763
|
|
|
$smcFunc['db_free_result']($request); |
|
764
|
|
View Code Duplication |
if (empty($_REQUEST['boards']) && empty($board)) |
|
|
|
|
|
|
765
|
|
|
unset($context['optimize_msg']['lowest']); |
|
766
|
|
|
else |
|
767
|
|
|
$context['optimize_msg']['lowest'] = $loops ? 'm.id_msg >= t.id_first_msg' : 'm.id_msg >= (t.id_last_msg - t.id_first_msg) / 2'; |
|
768
|
|
|
$loops++; |
|
769
|
|
|
} |
|
770
|
|
|
else |
|
771
|
|
|
$done = true; |
|
772
|
|
|
} |
|
773
|
|
|
$messages = array(); |
|
774
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
|
|
|
|
|
775
|
|
|
$messages[] = $row['id_msg']; |
|
776
|
|
|
$smcFunc['db_free_result']($request); |
|
777
|
|
|
|
|
778
|
|
|
if (empty($messages)) |
|
779
|
|
|
return array(); |
|
780
|
|
|
|
|
781
|
|
|
// Find the most recent posts this user can see. |
|
782
|
|
|
$request = $smcFunc['db_query']('', ' |
|
783
|
|
|
SELECT |
|
784
|
|
|
m.smileys_enabled, m.poster_time, m.id_msg, m.subject, m.body, m.id_topic, t.id_board, |
|
785
|
|
|
b.name AS bname, t.num_replies, m.id_member, m.icon, mf.id_member AS id_first_member, |
|
786
|
|
|
COALESCE(mem.real_name, m.poster_name) AS poster_name, mf.subject AS first_subject, |
|
787
|
|
|
COALESCE(memf.real_name, mf.poster_name) AS first_poster_name, |
|
788
|
|
|
COALESCE(mem.email_address, m.poster_email) AS poster_email, m.modified_time |
|
789
|
|
|
FROM {db_prefix}messages AS m |
|
790
|
|
|
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) |
|
791
|
|
|
INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg) |
|
792
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
|
793
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
|
794
|
|
|
LEFT JOIN {db_prefix}members AS memf ON (memf.id_member = mf.id_member) |
|
795
|
|
|
WHERE m.id_msg IN ({array_int:message_list}) |
|
796
|
|
|
' . (empty($board) ? '' : 'AND t.id_board = {int:current_board}') . ' |
|
797
|
|
|
ORDER BY m.id_msg DESC |
|
798
|
|
|
LIMIT {int:limit}', |
|
799
|
|
|
array( |
|
800
|
|
|
'limit' => $_GET['limit'], |
|
801
|
|
|
'current_board' => $board, |
|
802
|
|
|
'message_list' => $messages, |
|
803
|
|
|
) |
|
804
|
|
|
); |
|
805
|
|
|
$data = array(); |
|
806
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
807
|
|
|
{ |
|
808
|
|
|
// Limit the length of the message, if the option is set. |
|
809
|
|
View Code Duplication |
if (!empty($modSettings['xmlnews_maxlen']) && $smcFunc['strlen'](str_replace('<br>', "\n", $row['body'])) > $modSettings['xmlnews_maxlen']) |
|
|
|
|
|
|
810
|
|
|
$row['body'] = strtr($smcFunc['substr'](str_replace('<br>', "\n", $row['body']), 0, $modSettings['xmlnews_maxlen'] - 3), array("\n" => '<br>')) . '...'; |
|
811
|
|
|
|
|
812
|
|
|
$row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']); |
|
813
|
|
|
|
|
814
|
|
|
censorText($row['body']); |
|
815
|
|
|
censorText($row['subject']); |
|
816
|
|
|
|
|
817
|
|
|
// Doesn't work as well as news, but it kinda does.. |
|
818
|
|
|
if ($xml_format == 'rss' || $xml_format == 'rss2') |
|
819
|
|
|
$data[] = array( |
|
820
|
|
|
'title' => $row['subject'], |
|
821
|
|
|
'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], |
|
822
|
|
|
'description' => $row['body'], |
|
823
|
|
|
'author' => (allowedTo('moderate_forum') || (!empty($row['id_member']) && $row['id_member'] == $user_info['id'])) ? $row['poster_email'] : null, |
|
824
|
|
|
'category' => $row['bname'], |
|
825
|
|
|
'comments' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.0', |
|
826
|
|
|
'pubDate' => gmdate('D, d M Y H:i:s \G\M\T', $row['poster_time']), |
|
827
|
|
|
'guid' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] |
|
828
|
|
|
); |
|
829
|
|
|
elseif ($xml_format == 'rdf') |
|
830
|
|
|
$data[] = array( |
|
831
|
|
|
'title' => $row['subject'], |
|
832
|
|
|
'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], |
|
833
|
|
|
'description' => $row['body'], |
|
834
|
|
|
); |
|
835
|
|
|
elseif ($xml_format == 'atom') |
|
836
|
|
|
$data[] = array( |
|
837
|
|
|
'title' => $row['subject'], |
|
838
|
|
|
'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], |
|
839
|
|
|
'summary' => $row['body'], |
|
840
|
|
|
'category' => $row['bname'], |
|
841
|
|
|
'author' => array( |
|
842
|
|
|
'name' => $row['poster_name'], |
|
843
|
|
|
'email' => (allowedTo('moderate_forum') || (!empty($row['id_member']) && $row['id_member'] == $user_info['id'])) ? $row['poster_email'] : null, |
|
844
|
|
|
'uri' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : null, |
|
845
|
|
|
), |
|
846
|
|
|
'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['poster_time']), |
|
847
|
|
|
'updated' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', empty($row['modified_time']) ? $row['poster_time'] : $row['modified_time']), |
|
848
|
|
|
'id' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], |
|
849
|
|
|
); |
|
850
|
|
|
// A lot of information here. Should be enough to please the rss-ers. |
|
851
|
|
|
else |
|
852
|
|
|
$data[] = array( |
|
853
|
|
|
'time' => $smcFunc['htmlspecialchars'](strip_tags(timeformat($row['poster_time']))), |
|
854
|
|
|
'id' => $row['id_msg'], |
|
855
|
|
|
'subject' => $row['subject'], |
|
856
|
|
|
'body' => $row['body'], |
|
857
|
|
|
'starter' => array( |
|
858
|
|
|
'name' => $row['first_poster_name'], |
|
859
|
|
|
'id' => $row['id_first_member'], |
|
860
|
|
|
'link' => !empty($row['id_first_member']) ? $scripturl . '?action=profile;u=' . $row['id_first_member'] : '' |
|
861
|
|
|
), |
|
862
|
|
|
'poster' => array( |
|
863
|
|
|
'name' => $row['poster_name'], |
|
864
|
|
|
'id' => $row['id_member'], |
|
865
|
|
|
'link' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : '' |
|
866
|
|
|
), |
|
867
|
|
|
'topic' => array( |
|
868
|
|
|
'subject' => $row['first_subject'], |
|
869
|
|
|
'id' => $row['id_topic'], |
|
870
|
|
|
'link' => $scripturl . '?topic=' . $row['id_topic'] . '.new#new' |
|
871
|
|
|
), |
|
872
|
|
|
'board' => array( |
|
873
|
|
|
'name' => $row['bname'], |
|
874
|
|
|
'id' => $row['id_board'], |
|
875
|
|
|
'link' => $scripturl . '?board=' . $row['id_board'] . '.0' |
|
876
|
|
|
), |
|
877
|
|
|
'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] |
|
878
|
|
|
); |
|
879
|
|
|
} |
|
880
|
|
|
$smcFunc['db_free_result']($request); |
|
881
|
|
|
|
|
882
|
|
|
return $data; |
|
883
|
|
|
} |
|
884
|
|
|
|
|
885
|
|
|
/** |
|
886
|
|
|
* Get the profile information for member into an array, |
|
887
|
|
|
* which will be generated to match the xml_format. |
|
888
|
|
|
* @todo refactor. |
|
889
|
|
|
* |
|
890
|
|
|
* @param $xml_format The XML format. Can be 'atom', 'rdf', 'rss', 'rss2' or 'xml' |
|
891
|
|
|
* @return array An array profile data |
|
892
|
|
|
*/ |
|
893
|
|
|
function getXmlProfile($xml_format) |
|
894
|
|
|
{ |
|
895
|
|
|
global $scripturl, $memberContext, $user_profile, $user_info; |
|
896
|
|
|
|
|
897
|
|
|
// You must input a valid user.... |
|
898
|
|
|
if (empty($_GET['u']) || !loadMemberData((int) $_GET['u'])) |
|
899
|
|
|
return array(); |
|
900
|
|
|
|
|
901
|
|
|
// Make sure the id is a number and not "I like trying to hack the database". |
|
902
|
|
|
$_GET['u'] = (int) $_GET['u']; |
|
903
|
|
|
// Load the member's contextual information! |
|
904
|
|
|
if (!loadMemberContext($_GET['u']) || !allowedTo('profile_view')) |
|
905
|
|
|
return array(); |
|
906
|
|
|
|
|
907
|
|
|
// Okay, I admit it, I'm lazy. Stupid $_GET['u'] is long and hard to type. |
|
908
|
|
|
$profile = &$memberContext[$_GET['u']]; |
|
909
|
|
|
|
|
910
|
|
|
if ($xml_format == 'rss' || $xml_format == 'rss2') |
|
911
|
|
|
$data = array(array( |
|
912
|
|
|
'title' => $profile['name'], |
|
913
|
|
|
'link' => $scripturl . '?action=profile;u=' . $profile['id'], |
|
914
|
|
|
'description' => isset($profile['group']) ? $profile['group'] : $profile['post_group'], |
|
915
|
|
|
'comments' => $scripturl . '?action=pm;sa=send;u=' . $profile['id'], |
|
916
|
|
|
'pubDate' => gmdate('D, d M Y H:i:s \G\M\T', $user_profile[$profile['id']]['date_registered']), |
|
917
|
|
|
'guid' => $scripturl . '?action=profile;u=' . $profile['id'], |
|
918
|
|
|
)); |
|
919
|
|
|
elseif ($xml_format == 'rdf') |
|
920
|
|
|
$data = array(array( |
|
921
|
|
|
'title' => $profile['name'], |
|
922
|
|
|
'link' => $scripturl . '?action=profile;u=' . $profile['id'], |
|
923
|
|
|
'description' => isset($profile['group']) ? $profile['group'] : $profile['post_group'], |
|
924
|
|
|
)); |
|
925
|
|
|
elseif ($xml_format == 'atom') |
|
926
|
|
|
$data[] = array( |
|
|
|
|
|
|
927
|
|
|
'title' => $profile['name'], |
|
928
|
|
|
'link' => $scripturl . '?action=profile;u=' . $profile['id'], |
|
929
|
|
|
'summary' => isset($profile['group']) ? $profile['group'] : $profile['post_group'], |
|
930
|
|
|
'author' => array( |
|
931
|
|
|
'name' => $profile['real_name'], |
|
932
|
|
|
'email' => $profile['show_email'] ? $profile['email'] : null, |
|
933
|
|
|
'uri' => !empty($profile['website']) ? $profile['website']['url'] : null, |
|
934
|
|
|
), |
|
935
|
|
|
'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $user_profile[$profile['id']]['date_registered']), |
|
936
|
|
|
'updated' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $user_profile[$profile['id']]['last_login']), |
|
937
|
|
|
'id' => $scripturl . '?action=profile;u=' . $profile['id'], |
|
938
|
|
|
'logo' => !empty($profile['avatar']) ? $profile['avatar']['url'] : '', |
|
939
|
|
|
); |
|
940
|
|
|
else |
|
941
|
|
|
{ |
|
942
|
|
|
$data = array( |
|
943
|
|
|
'username' => $user_info['is_admin'] || $user_info['id'] == $profile['id'] ? $profile['username'] : '', |
|
944
|
|
|
'name' => $profile['name'], |
|
945
|
|
|
'link' => $scripturl . '?action=profile;u=' . $profile['id'], |
|
946
|
|
|
'posts' => $profile['posts'], |
|
947
|
|
|
'post-group' => $profile['post_group'], |
|
948
|
|
|
'language' => $profile['language'], |
|
949
|
|
|
'last-login' => gmdate('D, d M Y H:i:s \G\M\T', $user_profile[$profile['id']]['last_login']), |
|
950
|
|
|
'registered' => gmdate('D, d M Y H:i:s \G\M\T', $user_profile[$profile['id']]['date_registered']) |
|
951
|
|
|
); |
|
952
|
|
|
|
|
953
|
|
|
// Everything below here might not be set, and thus maybe shouldn't be displayed. |
|
954
|
|
|
if ($profile['gender']['name'] != '') |
|
955
|
|
|
$data['gender'] = $profile['gender']['name']; |
|
956
|
|
|
|
|
957
|
|
|
if ($profile['avatar']['name'] != '') |
|
958
|
|
|
$data['avatar'] = $profile['avatar']['url']; |
|
959
|
|
|
|
|
960
|
|
|
// If they are online, show an empty tag... no reason to put anything inside it. |
|
961
|
|
|
if ($profile['online']['is_online']) |
|
962
|
|
|
$data['online'] = ''; |
|
963
|
|
|
|
|
964
|
|
|
if ($profile['signature'] != '') |
|
965
|
|
|
$data['signature'] = $profile['signature']; |
|
966
|
|
|
if ($profile['blurb'] != '') |
|
967
|
|
|
$data['blurb'] = $profile['blurb']; |
|
968
|
|
|
if ($profile['title'] != '') |
|
969
|
|
|
$data['title'] = $profile['title']; |
|
970
|
|
|
|
|
971
|
|
|
if ($profile['website']['title'] != '') |
|
972
|
|
|
$data['website'] = array( |
|
973
|
|
|
'title' => $profile['website']['title'], |
|
974
|
|
|
'link' => $profile['website']['url'] |
|
975
|
|
|
); |
|
976
|
|
|
|
|
977
|
|
|
if ($profile['group'] != '') |
|
978
|
|
|
$data['position'] = $profile['group']; |
|
979
|
|
|
|
|
980
|
|
|
if ($profile['show_email']) |
|
981
|
|
|
$data['email'] = $profile['email']; |
|
982
|
|
|
|
|
983
|
|
|
if (!empty($profile['birth_date']) && substr($profile['birth_date'], 0, 4) != '0000') |
|
984
|
|
|
{ |
|
985
|
|
|
list ($birth_year, $birth_month, $birth_day) = sscanf($profile['birth_date'], '%d-%d-%d'); |
|
986
|
|
|
$datearray = getdate(forum_time()); |
|
987
|
|
|
$data['age'] = $datearray['year'] - $birth_year - (($datearray['mon'] > $birth_month || ($datearray['mon'] == $birth_month && $datearray['mday'] >= $birth_day)) ? 0 : 1); |
|
988
|
|
|
} |
|
989
|
|
|
} |
|
990
|
|
|
|
|
991
|
|
|
// Save some memory. |
|
992
|
|
|
unset($profile, $memberContext[$_GET['u']]); |
|
993
|
|
|
|
|
994
|
|
|
return $data; |
|
995
|
|
|
} |
|
996
|
|
|
|
|
997
|
|
|
?> |
|
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.