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 2019 Simple Machines and individual contributors |
||||
11 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||||
12 | * |
||||
13 | * @version 2.1 RC2 |
||||
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, $settings, $cache_enable; |
||||
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 | // Some general metadata for this feed. We'll change some of these values below. |
||||
49 | $feed_meta = array( |
||||
50 | 'title' => '', |
||||
51 | 'desc' => $txt['xml_rss_desc'], |
||||
52 | 'author' => $context['forum_name'], |
||||
53 | 'source' => $scripturl, |
||||
54 | 'rights' => '© ' . date('Y') . ' ' . $context['forum_name'], |
||||
55 | 'icon' => !empty($settings['og_image']) ? $settings['og_image'] : $boardurl . '/favicon.ico', |
||||
56 | 'language' => !empty($txt['lang_locale']) ? str_replace("_", "-", substr($txt['lang_locale'], 0, strcspn($txt['lang_locale'], "."))) : 'en', |
||||
57 | ); |
||||
58 | |||||
59 | // Handle the cases where a board, boards, or category is asked for. |
||||
60 | $query_this_board = 1; |
||||
61 | $context['optimize_msg'] = array( |
||||
62 | 'highest' => 'm.id_msg <= b.id_last_msg', |
||||
63 | ); |
||||
64 | if (!empty($_REQUEST['c']) && empty($board)) |
||||
65 | { |
||||
66 | $_REQUEST['c'] = explode(',', $_REQUEST['c']); |
||||
67 | foreach ($_REQUEST['c'] as $i => $c) |
||||
68 | $_REQUEST['c'][$i] = (int) $c; |
||||
69 | |||||
70 | if (count($_REQUEST['c']) == 1) |
||||
71 | { |
||||
72 | $request = $smcFunc['db_query']('', ' |
||||
73 | SELECT name |
||||
74 | FROM {db_prefix}categories |
||||
75 | WHERE id_cat = {int:current_category}', |
||||
76 | array( |
||||
77 | 'current_category' => (int) $_REQUEST['c'][0], |
||||
78 | ) |
||||
79 | ); |
||||
80 | list ($feed_meta['title']) = $smcFunc['db_fetch_row']($request); |
||||
81 | $smcFunc['db_free_result']($request); |
||||
82 | |||||
83 | $feed_meta['title'] = ' - ' . strip_tags($feed_meta['title']); |
||||
84 | } |
||||
85 | |||||
86 | $request = $smcFunc['db_query']('', ' |
||||
87 | SELECT b.id_board, b.num_posts |
||||
88 | FROM {db_prefix}boards AS b |
||||
89 | WHERE b.id_cat IN ({array_int:current_category_list}) |
||||
90 | AND {query_see_board}', |
||||
91 | array( |
||||
92 | 'current_category_list' => $_REQUEST['c'], |
||||
93 | ) |
||||
94 | ); |
||||
95 | $total_cat_posts = 0; |
||||
96 | $boards = array(); |
||||
97 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||||
98 | { |
||||
99 | $boards[] = $row['id_board']; |
||||
100 | $total_cat_posts += $row['num_posts']; |
||||
101 | } |
||||
102 | $smcFunc['db_free_result']($request); |
||||
103 | |||||
104 | if (!empty($boards)) |
||||
105 | $query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')'; |
||||
106 | |||||
107 | // Try to limit the number of messages we look through. |
||||
108 | if ($total_cat_posts > 100 && $total_cat_posts > $modSettings['totalMessages'] / 15) |
||||
109 | $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 400 - $_GET['limit'] * 5); |
||||
110 | } |
||||
111 | elseif (!empty($_REQUEST['boards'])) |
||||
112 | { |
||||
113 | $_REQUEST['boards'] = explode(',', $_REQUEST['boards']); |
||||
114 | foreach ($_REQUEST['boards'] as $i => $b) |
||||
115 | $_REQUEST['boards'][$i] = (int) $b; |
||||
116 | |||||
117 | $request = $smcFunc['db_query']('', ' |
||||
118 | SELECT b.id_board, b.num_posts, b.name |
||||
119 | FROM {db_prefix}boards AS b |
||||
120 | WHERE b.id_board IN ({array_int:board_list}) |
||||
121 | AND {query_see_board} |
||||
122 | LIMIT {int:limit}', |
||||
123 | array( |
||||
124 | 'board_list' => $_REQUEST['boards'], |
||||
125 | 'limit' => count($_REQUEST['boards']), |
||||
126 | ) |
||||
127 | ); |
||||
128 | |||||
129 | // Either the board specified doesn't exist or you have no access. |
||||
130 | $num_boards = $smcFunc['db_num_rows']($request); |
||||
131 | if ($num_boards == 0) |
||||
132 | fatal_lang_error('no_board'); |
||||
133 | |||||
134 | $total_posts = 0; |
||||
135 | $boards = array(); |
||||
136 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||||
137 | { |
||||
138 | if ($num_boards == 1) |
||||
139 | $feed_meta['title'] = ' - ' . strip_tags($row['name']); |
||||
140 | |||||
141 | $boards[] = $row['id_board']; |
||||
142 | $total_posts += $row['num_posts']; |
||||
143 | } |
||||
144 | $smcFunc['db_free_result']($request); |
||||
145 | |||||
146 | if (!empty($boards)) |
||||
147 | $query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')'; |
||||
148 | |||||
149 | // The more boards, the more we're going to look through... |
||||
150 | if ($total_posts > 100 && $total_posts > $modSettings['totalMessages'] / 12) |
||||
151 | $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 500 - $_GET['limit'] * 5); |
||||
152 | } |
||||
153 | elseif (!empty($board)) |
||||
154 | { |
||||
155 | $request = $smcFunc['db_query']('', ' |
||||
156 | SELECT num_posts |
||||
157 | FROM {db_prefix}boards |
||||
158 | WHERE id_board = {int:current_board} |
||||
159 | LIMIT 1', |
||||
160 | array( |
||||
161 | 'current_board' => $board, |
||||
162 | ) |
||||
163 | ); |
||||
164 | list ($total_posts) = $smcFunc['db_fetch_row']($request); |
||||
165 | $smcFunc['db_free_result']($request); |
||||
166 | |||||
167 | $feed_meta['title'] = ' - ' . strip_tags($board_info['name']); |
||||
168 | $feed_meta['source'] .= '?board=' . $board . '.0'; |
||||
169 | |||||
170 | $query_this_board = 'b.id_board = ' . $board; |
||||
171 | |||||
172 | // Try to look through just a few messages, if at all possible. |
||||
173 | if ($total_posts > 80 && $total_posts > $modSettings['totalMessages'] / 10) |
||||
174 | $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 600 - $_GET['limit'] * 5); |
||||
175 | } |
||||
176 | else |
||||
177 | { |
||||
178 | $query_this_board = '{query_see_board}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' |
||||
179 | AND b.id_board != ' . $modSettings['recycle_board'] : ''); |
||||
180 | $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 100 - $_GET['limit'] * 5); |
||||
181 | } |
||||
182 | |||||
183 | // Show in rss or proprietary format? |
||||
184 | $xml_format = isset($_GET['type']) && in_array($_GET['type'], array('smf', 'rss', 'rss2', 'atom', 'rdf')) ? $_GET['type'] : 'rss2'; |
||||
185 | |||||
186 | // @todo Birthdays? |
||||
187 | |||||
188 | // List all the different types of data they can pull. |
||||
189 | $subActions = array( |
||||
190 | 'recent' => array('getXmlRecent', 'recent-post'), |
||||
191 | 'news' => array('getXmlNews', 'article'), |
||||
192 | 'members' => array('getXmlMembers', 'member'), |
||||
193 | 'profile' => array('getXmlProfile', null), |
||||
194 | ); |
||||
195 | |||||
196 | // Easy adding of sub actions |
||||
197 | call_integration_hook('integrate_xmlfeeds', array(&$subActions)); |
||||
198 | |||||
199 | if (empty($_GET['sa']) || !isset($subActions[$_GET['sa']])) |
||||
200 | $_GET['sa'] = 'recent'; |
||||
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($smcFunc['json_encode']($cachekey) . (!empty($query_this_board) ? $query_this_board : '')); |
||||
208 | $cache_t = microtime(true); |
||||
209 | |||||
210 | // Get the associative array representing the xml. |
||||
211 | if (!empty($cache_enable) && (!$user_info['is_guest'] || $cache_enable >= 3)) |
||||
212 | $xml_data = cache_get_data('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, 240); |
||||
213 | if (empty($xml_data)) |
||||
214 | { |
||||
215 | $call = call_helper($subActions[$_GET['sa']][0], true); |
||||
216 | |||||
217 | if (!empty($call)) |
||||
218 | $xml_data = call_user_func($call, $xml_format); |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
219 | |||||
220 | if (!empty($cache_enable) && (($user_info['is_guest'] && $cache_enable >= 3) |
||||
221 | || (!$user_info['is_guest'] && (microtime(true) - $cache_t > 0.2)))) |
||||
222 | cache_put_data('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, $xml_data, 240); |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
223 | } |
||||
224 | |||||
225 | $feed_meta['title'] = $smcFunc['htmlspecialchars'](strip_tags($context['forum_name'])) . (isset($feed_meta['title']) ? $feed_meta['title'] : ''); |
||||
226 | |||||
227 | // Allow mods to add extra namespaces and tags to the feed/channel |
||||
228 | $namespaces = array( |
||||
229 | 'rss' => array(), |
||||
230 | 'rss2' => array('atom' => 'http://www.w3.org/2005/Atom'), |
||||
231 | 'atom' => array('' => 'http://www.w3.org/2005/Atom'), |
||||
232 | 'rdf' => array( |
||||
233 | '' => 'http://purl.org/rss/1.0/', |
||||
234 | 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', |
||||
235 | 'dc' => 'http://purl.org/dc/elements/1.1/', |
||||
236 | ), |
||||
237 | 'smf' => array( |
||||
238 | '' => 'http://www.simplemachines.org/xml/' . $_GET['sa'], |
||||
239 | 'smf' => 'http://www.simplemachines.org/', |
||||
240 | ), |
||||
241 | ); |
||||
242 | $extraFeedTags = array( |
||||
243 | 'rss' => array(), |
||||
244 | 'rss2' => array(), |
||||
245 | 'atom' => array(), |
||||
246 | 'rdf' => array(), |
||||
247 | 'smf' => array(), |
||||
248 | ); |
||||
249 | |||||
250 | // Allow mods to specify any keys that need special handling |
||||
251 | $forceCdataKeys = array(); |
||||
252 | $nsKeys = array(); |
||||
253 | |||||
254 | // Remember this, just in case... |
||||
255 | $orig_feed_meta = $feed_meta; |
||||
256 | |||||
257 | // If mods want to do somthing with this feed, let them do that now. |
||||
258 | // Provide the feed's data, metadata, namespaces, extra feed-level tags, keys that need special handling, the feed format, and the requested subaction |
||||
259 | call_integration_hook('integrate_xml_data', array(&$xml_data, &$feed_meta, &$namespaces, &$extraFeedTags, &$forceCdataKeys, &$nsKeys, $xml_format, $_GET['sa'])); |
||||
260 | |||||
261 | // These can't be empty |
||||
262 | foreach (array('title', 'desc', 'source') as $mkey) |
||||
263 | $feed_meta[$mkey] = !empty($feed_meta[$mkey]) ? $feed_meta[$mkey] : $orig_feed_meta[$mkey]; |
||||
264 | |||||
265 | // Sanitize basic feed metadata values |
||||
266 | foreach ($feed_meta as $mkey => $mvalue) |
||||
267 | $feed_meta[$mkey] = cdata_parse(strip_tags(fix_possible_url($feed_meta[$mkey]))); |
||||
268 | |||||
269 | $ns_string = ''; |
||||
270 | if (!empty($namespaces[$xml_format])) |
||||
271 | { |
||||
272 | foreach ($namespaces[$xml_format] as $nsprefix => $nsurl) |
||||
273 | $ns_string .= ' xmlns' . ($nsprefix !== '' ? ':' : '') . $nsprefix . '="' . $nsurl . '"'; |
||||
274 | } |
||||
275 | |||||
276 | $extraFeedTags_string = ''; |
||||
277 | if (!empty($extraFeedTags[$xml_format])) |
||||
278 | { |
||||
279 | $indent = "\t" . ($xml_format !== 'atom' ? "\t" : ''); |
||||
280 | foreach ($extraFeedTags[$xml_format] as $extraTag) |
||||
281 | $extraFeedTags_string .= "\n" . $indent . $extraTag; |
||||
282 | } |
||||
283 | |||||
284 | // This is an xml file.... |
||||
285 | ob_end_clean(); |
||||
286 | if (!empty($modSettings['enableCompressedOutput'])) |
||||
287 | @ob_start('ob_gzhandler'); |
||||
288 | else |
||||
289 | ob_start(); |
||||
290 | |||||
291 | if ($xml_format == 'smf' || isset($_REQUEST['debug'])) |
||||
292 | header('content-type: text/xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set'])); |
||||
293 | elseif ($xml_format == 'rss' || $xml_format == 'rss2') |
||||
294 | header('content-type: application/rss+xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set'])); |
||||
295 | elseif ($xml_format == 'atom') |
||||
296 | header('content-type: application/atom+xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set'])); |
||||
297 | elseif ($xml_format == 'rdf') |
||||
298 | header('content-type: ' . (isBrowser('ie') ? 'text/xml' : 'application/rdf+xml') . '; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set'])); |
||||
299 | |||||
300 | // First, output the xml header. |
||||
301 | echo '<?xml version="1.0" encoding="', $context['character_set'], '"?' . '>'; |
||||
302 | |||||
303 | // Are we outputting an rss feed or one with more information? |
||||
304 | if ($xml_format == 'rss' || $xml_format == 'rss2') |
||||
305 | { |
||||
306 | if ($xml_format == 'rss2') |
||||
307 | foreach ($_REQUEST as $var => $val) |
||||
308 | if (in_array($var, array('action', 'sa', 'type', 'board', 'boards', 'c', 'u', 'limit'))) |
||||
309 | $url_parts[] = $var . '=' . (is_array($val) ? implode(',', $val) : $val); |
||||
310 | |||||
311 | // Start with an RSS 2.0 header. |
||||
312 | echo ' |
||||
313 | <rss version=', $xml_format == 'rss2' ? '"2.0"' : '"0.92"', ' xml:lang="', strtr($txt['lang_locale'], '_', '-'), '"', $ns_string, '> |
||||
314 | <channel> |
||||
315 | <title>', $feed_meta['title'], '</title> |
||||
316 | <link>', $feed_meta['source'], '</link> |
||||
317 | <description>', $feed_meta['desc'], '</description>', |
||||
318 | !empty($feed_meta['icon']) ? ' |
||||
319 | <image> |
||||
320 | <url>' . $feed_meta['icon'] . '</url> |
||||
321 | <title>' . $feed_meta['title'] . '</title> |
||||
322 | <link>' . $feed_meta['source'] . '</link> |
||||
323 | </image>' : '', |
||||
324 | !empty($feed_meta['rights']) ? ' |
||||
325 | <copyright>' . $feed_meta['rights'] . '</copyright>' : '', |
||||
326 | !empty($feed_meta['language']) ? ' |
||||
327 | <language>' . $feed_meta['language'] . '</language>' : ''; |
||||
328 | |||||
329 | // RSS2 calls for this. |
||||
330 | if ($xml_format == 'rss2') |
||||
331 | echo ' |
||||
332 | <atom:link rel="self" type="application/rss+xml" href="', $scripturl, !empty($url_parts) ? '?' . implode(';', $url_parts) : '', '" />'; |
||||
333 | |||||
334 | echo $extraFeedTags_string; |
||||
335 | |||||
336 | // Output all of the associative array, start indenting with 2 tabs, and name everything "item". |
||||
337 | dumpTags($xml_data, 2, null, $xml_format, $forceCdataKeys, $nsKeys); |
||||
338 | |||||
339 | // Output the footer of the xml. |
||||
340 | echo ' |
||||
341 | </channel> |
||||
342 | </rss>'; |
||||
343 | } |
||||
344 | elseif ($xml_format == 'atom') |
||||
345 | { |
||||
346 | foreach ($_REQUEST as $var => $val) |
||||
347 | if (in_array($var, array('action', 'sa', 'type', 'board', 'boards', 'c', 'u', 'limit'))) |
||||
348 | $url_parts[] = $var . '=' . (is_array($val) ? implode(',', $val) : $val); |
||||
349 | |||||
350 | echo ' |
||||
351 | <feed', $ns_string, !empty($feed_meta['language']) ? ' xml:lang="' . $feed_meta['language'] . '"' : '', '> |
||||
352 | <title>', $feed_meta['title'], '</title> |
||||
353 | <link rel="alternate" type="text/html" href="', $feed_meta['source'], '" /> |
||||
354 | <link rel="self" type="application/atom+xml" href="', $scripturl, !empty($url_parts) ? '?' . implode(';', $url_parts) : '', '" /> |
||||
355 | <updated>', gmstrftime('%Y-%m-%dT%H:%M:%SZ'), '</updated> |
||||
356 | <id>', $feed_meta['source'], '</id> |
||||
357 | <subtitle>', $feed_meta['desc'], '</subtitle> |
||||
358 | <generator uri="https://www.simplemachines.org" version="', SMF_VERSION, '">SMF</generator>', |
||||
359 | !empty($feed_meta['icon']) ? ' |
||||
360 | <icon>' . $feed_meta['icon'] . '</icon>' : '', |
||||
361 | !empty($feed_meta['author']) ? ' |
||||
362 | <author> |
||||
363 | <name>' . $feed_meta['author'] . '</name> |
||||
364 | </author>' : '', |
||||
365 | !empty($feed_meta['rights']) ? ' |
||||
366 | <rights>' . $feed_meta['rights'] . '</rights>' : ''; |
||||
367 | |||||
368 | echo $extraFeedTags_string; |
||||
369 | |||||
370 | dumpTags($xml_data, 1, null, $xml_format, $forceCdataKeys, $nsKeys); |
||||
371 | |||||
372 | echo ' |
||||
373 | </feed>'; |
||||
374 | } |
||||
375 | elseif ($xml_format == 'rdf') |
||||
376 | { |
||||
377 | echo ' |
||||
378 | <rdf:RDF', $ns_string, '> |
||||
379 | <channel rdf:about="', $scripturl, '"> |
||||
380 | <title>', $feed_meta['title'], '</title> |
||||
381 | <link>', $feed_meta['source'], '</link> |
||||
382 | <description>', $feed_meta['desc'], '</description>'; |
||||
383 | |||||
384 | echo $extraFeedTags_string; |
||||
385 | |||||
386 | echo ' |
||||
387 | <items> |
||||
388 | <rdf:Seq>'; |
||||
389 | |||||
390 | foreach ($xml_data as $item) |
||||
391 | { |
||||
392 | $link = array_filter($item['content'], function($e) |
||||
393 | { |
||||
394 | return ($e['tag'] == 'link'); |
||||
395 | }); |
||||
396 | $link = array_pop($link); |
||||
397 | |||||
398 | echo ' |
||||
399 | <rdf:li rdf:resource="', $link['content'], '" />'; |
||||
400 | } |
||||
401 | |||||
402 | echo ' |
||||
403 | </rdf:Seq> |
||||
404 | </items> |
||||
405 | </channel> |
||||
406 | '; |
||||
407 | |||||
408 | dumpTags($xml_data, 1, null, $xml_format, $forceCdataKeys, $nsKeys); |
||||
409 | |||||
410 | echo ' |
||||
411 | </rdf:RDF>'; |
||||
412 | } |
||||
413 | // Otherwise, we're using our proprietary formats - they give more data, though. |
||||
414 | else |
||||
415 | { |
||||
416 | echo ' |
||||
417 | <smf:xml-feed xml:lang="', strtr($txt['lang_locale'], '_', '-'), '"', $ns_string, '>'; |
||||
418 | |||||
419 | // Hard to imagine anyone wanting to add these for the proprietary format, but just in case... |
||||
420 | echo $extraFeedTags_string; |
||||
421 | |||||
422 | // Dump out that associative array. Indent properly.... and use the right names for the base elements. |
||||
423 | dumpTags($xml_data, 1, $subActions[$_GET['sa']][1], $xml_format, $forceCdataKeys, $nsKeys); |
||||
424 | |||||
425 | echo ' |
||||
426 | </smf:xml-feed>'; |
||||
427 | } |
||||
428 | |||||
429 | obExit(false); |
||||
430 | } |
||||
431 | |||||
432 | /** |
||||
433 | * Called from dumpTags to convert data to xml |
||||
434 | * Finds urls for local site and sanitizes them |
||||
435 | * |
||||
436 | * @param string $val A string containing a possible URL |
||||
437 | * @return string $val The string with any possible URLs sanitized |
||||
438 | */ |
||||
439 | function fix_possible_url($val) |
||||
440 | { |
||||
441 | global $modSettings, $context, $scripturl; |
||||
442 | |||||
443 | if (substr($val, 0, strlen($scripturl)) != $scripturl) |
||||
444 | return $val; |
||||
445 | |||||
446 | call_integration_hook('integrate_fix_url', array(&$val)); |
||||
447 | |||||
448 | 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'])) |
||||
449 | return $val; |
||||
450 | |||||
451 | $val = preg_replace_callback('~\b' . preg_quote($scripturl, '~') . '\?((?:board|topic)=[^#"]+)(#[^"]*)?$~', function($m) use ($scripturl) |
||||
452 | { |
||||
453 | return $scripturl . '/' . strtr("$m[1]", '&;=', '//,') . '.html' . (isset($m[2]) ? $m[2] : ""); |
||||
454 | }, $val); |
||||
455 | return $val; |
||||
456 | } |
||||
457 | |||||
458 | /** |
||||
459 | * Ensures supplied data is properly encapsulated in cdata xml tags |
||||
460 | * Called from getXmlProfile in News.php |
||||
461 | * |
||||
462 | * @param string $data XML data |
||||
463 | * @param string $ns A namespace prefix for the XML data elements (used by mods, maybe) |
||||
464 | * @param boolean $force If true, enclose the XML data in cdata tags no matter what (used by mods, maybe) |
||||
465 | * @return string The XML data enclosed in cdata tags when necessary |
||||
466 | */ |
||||
467 | function cdata_parse($data, $ns = '', $force = false) |
||||
468 | { |
||||
469 | global $smcFunc; |
||||
470 | |||||
471 | // Do we even need to do this? |
||||
472 | if (strpbrk($data, '<>&') == false && $force !== true) |
||||
0 ignored issues
–
show
|
|||||
473 | return $data; |
||||
474 | |||||
475 | $cdata = '<; $pos < $n; null) |
||||
478 | { |
||||
479 | $positions = array( |
||||
480 | $smcFunc['strpos']($data, '&', $pos), |
||||
481 | $smcFunc['strpos']($data, ']', $pos), |
||||
482 | ); |
||||
483 | if ($ns != '') |
||||
484 | $positions[] = $smcFunc['strpos']($data, '<', $pos); |
||||
485 | foreach ($positions as $k => $dummy) |
||||
486 | { |
||||
487 | if ($dummy === false) |
||||
488 | unset($positions[$k]); |
||||
489 | } |
||||
490 | |||||
491 | $old = $pos; |
||||
492 | $pos = empty($positions) ? $n : min($positions); |
||||
493 | |||||
494 | if ($pos - $old > 0) |
||||
495 | $cdata .= $smcFunc['substr']($data, $old, $pos - $old); |
||||
496 | if ($pos >= $n) |
||||
497 | break; |
||||
498 | |||||
499 | if ($smcFunc['substr']($data, $pos, 1) == '<') |
||||
500 | { |
||||
501 | $pos2 = $smcFunc['strpos']($data, '>', $pos); |
||||
502 | if ($pos2 === false) |
||||
503 | $pos2 = $n; |
||||
504 | if ($smcFunc['substr']($data, $pos + 1, 1) == '/') |
||||
505 | $cdata .= ']]></' . $ns . ':' . $smcFunc['substr']($data, $pos + 2, $pos2 - $pos - 1) . '<![CDATA['; |
||||
506 | else |
||||
507 | $cdata .= ']]><' . $ns . ':' . $smcFunc['substr']($data, $pos + 1, $pos2 - $pos) . '< == ']') |
||||
511 | { |
||||
512 | $cdata .= ']]>]< == '&') |
||||
516 | { |
||||
517 | $pos2 = $smcFunc['strpos']($data, ';', $pos); |
||||
518 | if ($pos2 === false) |
||||
519 | $pos2 = $n; |
||||
520 | $ent = $smcFunc['substr']($data, $pos + 1, $pos2 - $pos - 1); |
||||
521 | |||||
522 | if ($smcFunc['substr']($data, $pos + 1, 1) == '#') |
||||
523 | $cdata .= ']]>' . $smcFunc['substr']($data, $pos, $pos2 - $pos + 1) . '<![CDATA['; |
||||
524 | elseif (in_array($ent, array('amp', 'lt', 'gt', 'quot'))) |
||||
525 | $cdata .= ']]>' . $smcFunc['substr']($data, $pos, $pos2 - $pos + 1) . '<![CDATA['; |
||||
526 | |||||
527 | $pos = $pos2 + 1; |
||||
528 | } |
||||
529 | } |
||||
530 | |||||
531 | $cdata .= ']]>'; |
||||
532 | |||||
533 | return strtr($cdata, array('<![CDATA[]]>' => '')); |
||||
534 | } |
||||
535 | |||||
536 | /** |
||||
537 | * Formats data retrieved in other functions into xml format. |
||||
538 | * Additionally formats data based on the specific format passed. |
||||
539 | * This function is recursively called to handle sub arrays of data. |
||||
540 | * |
||||
541 | * @param array $data The array to output as xml data |
||||
542 | * @param int $i The amount of indentation to use. |
||||
543 | * @param null|string $tag |
||||
544 | * @param string $xml_format The format to use ('atom', 'rss', 'rss2' or empty for plain XML) |
||||
545 | * @param array $forceCdataKeys A list of keys on which to force cdata wrapping (used by mods, maybe) |
||||
546 | * @param array $nsKeys Key-value pairs of namespace prefixes to pass to cdata_parse() (used by mods, maybe) |
||||
547 | */ |
||||
548 | function dumpTags($data, $i, $tag = null, $xml_format = '', $forceCdataKeys = array(), $nsKeys = array()) |
||||
549 | { |
||||
550 | // Wrap the values of these keys into CDATA tags |
||||
551 | $keysToCdata = array( |
||||
552 | 'title', |
||||
553 | 'name', |
||||
554 | 'description', |
||||
555 | 'summary', |
||||
556 | 'subject', |
||||
557 | 'body', |
||||
558 | 'username', |
||||
559 | 'signature', |
||||
560 | 'position', |
||||
561 | 'language', |
||||
562 | 'gender', |
||||
563 | 'blurb', |
||||
564 | ); |
||||
565 | if ($xml_format != 'atom') |
||||
566 | $keysToCdata[] = 'category'; |
||||
567 | |||||
568 | if (!empty($forceCdataKeys)) |
||||
569 | { |
||||
570 | $keysToCdata = array_merge($keysToCdata, $forceCdataKeys); |
||||
571 | $keysToCdata = array_unique($keysToCdata); |
||||
572 | } |
||||
573 | |||||
574 | // For every array in the data... |
||||
575 | foreach ($data as $element) |
||||
576 | { |
||||
577 | // If a tag was passed, use it instead of the key. |
||||
578 | $key = isset($tag) ? $tag : (isset($element['tag']) ? $element['tag'] : null); |
||||
579 | $val = isset($element['content']) ? $element['content'] : null; |
||||
580 | $attrs = isset($element['attributes']) ? $element['attributes'] : null; |
||||
581 | |||||
582 | // Skip it, it's been set to null. |
||||
583 | if ($key === null || ($val === null && $attrs === null)) |
||||
584 | continue; |
||||
585 | |||||
586 | $forceCdata = in_array($key, $forceCdataKeys); |
||||
587 | $ns = !empty($nsKeys[$key]) ? $nsKeys[$key] : ''; |
||||
588 | |||||
589 | // First let's indent! |
||||
590 | echo "\n", str_repeat("\t", $i); |
||||
591 | |||||
592 | // Beginning tag. |
||||
593 | echo '<', $key; |
||||
594 | |||||
595 | if (!empty($attrs)) |
||||
596 | { |
||||
597 | foreach ($attrs as $attr_key => $attr_value) |
||||
598 | echo ' ', $attr_key, '="', fix_possible_url($attr_value), '"'; |
||||
599 | } |
||||
600 | |||||
601 | // If it's empty, simply output an empty element. |
||||
602 | if (empty($val)) |
||||
603 | { |
||||
604 | echo ' />'; |
||||
605 | } |
||||
606 | else |
||||
607 | { |
||||
608 | echo '>'; |
||||
609 | |||||
610 | // The element's value. |
||||
611 | if (is_array($val)) |
||||
612 | { |
||||
613 | // An array. Dump it, and then indent the tag. |
||||
614 | dumpTags($val, $i + 1, null, $xml_format, $forceCdataKeys, $nsKeys); |
||||
615 | echo "\n", str_repeat("\t", $i); |
||||
616 | } |
||||
617 | // A string with returns in it.... show this as a multiline element. |
||||
618 | elseif (strpos($val, "\n") !== false) |
||||
619 | echo "\n", in_array($key, $keysToCdata) ? cdata_parse(fix_possible_url($val), $ns, $forceCdata) : fix_possible_url($val), "\n", str_repeat("\t", $i); |
||||
620 | // A simple string. |
||||
621 | else |
||||
622 | echo in_array($key, $keysToCdata) ? cdata_parse(fix_possible_url($val), $ns, $forceCdata) : fix_possible_url($val); |
||||
623 | |||||
624 | // Ending tag. |
||||
625 | echo '</', $key, '>'; |
||||
626 | } |
||||
627 | } |
||||
628 | } |
||||
629 | |||||
630 | /** |
||||
631 | * Retrieve the list of members from database. |
||||
632 | * The array will be generated to match the format. |
||||
633 | * |
||||
634 | * @todo get the list of members from Subs-Members. |
||||
635 | * |
||||
636 | * @param string $xml_format The format to use. Can be 'atom', 'rdf', 'rss', 'rss2' or 'smf' |
||||
637 | * @return array An array of arrays of feed items. Each array has keys corresponding to the appropriate tags for the specified format. |
||||
638 | */ |
||||
639 | function getXmlMembers($xml_format) |
||||
640 | { |
||||
641 | global $scripturl, $smcFunc; |
||||
642 | |||||
643 | if (!allowedTo('view_mlist')) |
||||
644 | return array(); |
||||
645 | |||||
646 | // Find the most recent members. |
||||
647 | $request = $smcFunc['db_query']('', ' |
||||
648 | SELECT id_member, member_name, real_name, date_registered, last_login |
||||
649 | FROM {db_prefix}members |
||||
650 | ORDER BY id_member DESC |
||||
651 | LIMIT {int:limit}', |
||||
652 | array( |
||||
653 | 'limit' => $_GET['limit'], |
||||
654 | ) |
||||
655 | ); |
||||
656 | $data = array(); |
||||
657 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||||
658 | { |
||||
659 | // Create a GUID for each member using the tag URI scheme |
||||
660 | $guid = 'tag:' . parse_url($scripturl, PHP_URL_HOST) . ',' . gmdate('Y-m-d', $row['date_registered']) . ':member=' . $row['id_member']; |
||||
661 | |||||
662 | // Make the data look rss-ish. |
||||
663 | if ($xml_format == 'rss' || $xml_format == 'rss2') |
||||
664 | $data[] = array( |
||||
665 | 'tag' => 'item', |
||||
666 | 'content' => array( |
||||
667 | array( |
||||
668 | 'tag' => 'title', |
||||
669 | 'content' => $row['real_name'], |
||||
670 | ), |
||||
671 | array( |
||||
672 | 'tag' => 'link', |
||||
673 | 'content' => $scripturl . '?action=profile;u=' . $row['id_member'], |
||||
674 | ), |
||||
675 | array( |
||||
676 | 'tag' => 'comments', |
||||
677 | 'content' => $scripturl . '?action=pm;sa=send;u=' . $row['id_member'], |
||||
678 | ), |
||||
679 | array( |
||||
680 | 'tag' => 'pubDate', |
||||
681 | 'content' => gmdate('D, d M Y H:i:s \G\M\T', $row['date_registered']), |
||||
682 | ), |
||||
683 | array( |
||||
684 | 'tag' => 'guid', |
||||
685 | 'content' => $guid, |
||||
686 | 'attributes' => array( |
||||
687 | 'isPermaLink' => 'false', |
||||
688 | ), |
||||
689 | ), |
||||
690 | ), |
||||
691 | ); |
||||
692 | elseif ($xml_format == 'rdf') |
||||
693 | $data[] = array( |
||||
694 | 'tag' => 'item', |
||||
695 | 'attributes' => array('rdf:about' => $scripturl . '?action=profile;u=' . $row['id_member']), |
||||
696 | 'content' => array( |
||||
697 | array( |
||||
698 | 'tag' => 'dc:format', |
||||
699 | 'content' => 'text/html', |
||||
700 | ), |
||||
701 | array( |
||||
702 | 'tag' => 'title', |
||||
703 | 'content' => $row['real_name'], |
||||
704 | ), |
||||
705 | array( |
||||
706 | 'tag' => 'link', |
||||
707 | 'content' => $scripturl . '?action=profile;u=' . $row['id_member'], |
||||
708 | ), |
||||
709 | ), |
||||
710 | ); |
||||
711 | elseif ($xml_format == 'atom') |
||||
712 | $data[] = array( |
||||
713 | 'tag' => 'entry', |
||||
714 | 'content' => array( |
||||
715 | array( |
||||
716 | 'tag' => 'title', |
||||
717 | 'content' => $row['real_name'], |
||||
718 | ), |
||||
719 | array( |
||||
720 | 'tag' => 'link', |
||||
721 | 'attributes' => array( |
||||
722 | 'rel' => 'alternate', |
||||
723 | 'type' => 'text/html', |
||||
724 | 'href' => $scripturl . '?action=profile;u=' . $row['id_member'], |
||||
725 | ), |
||||
726 | ), |
||||
727 | array( |
||||
728 | 'tag' => 'published', |
||||
729 | 'content' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['date_registered']), |
||||
730 | ), |
||||
731 | array( |
||||
732 | 'tag' => 'updated', |
||||
733 | 'content' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['last_login']), |
||||
734 | ), |
||||
735 | array( |
||||
736 | 'tag' => 'id', |
||||
737 | 'content' => $guid, |
||||
738 | ), |
||||
739 | ), |
||||
740 | ); |
||||
741 | // More logical format for the data, but harder to apply. |
||||
742 | else |
||||
743 | $data[] = array( |
||||
744 | 'tag' => 'member', |
||||
745 | 'content' => array( |
||||
746 | array( |
||||
747 | 'tag' => 'name', |
||||
748 | 'content' => $row['real_name'], |
||||
749 | ), |
||||
750 | array( |
||||
751 | 'tag' => 'time', |
||||
752 | 'content' => $smcFunc['htmlspecialchars'](strip_tags(timeformat($row['date_registered']))), |
||||
753 | ), |
||||
754 | array( |
||||
755 | 'tag' => 'id', |
||||
756 | 'content' => $row['id_member'], |
||||
757 | ), |
||||
758 | array( |
||||
759 | 'tag' => 'link', |
||||
760 | 'content' => $scripturl . '?action=profile;u=' . $row['id_member'], |
||||
761 | ), |
||||
762 | ), |
||||
763 | ); |
||||
764 | } |
||||
765 | $smcFunc['db_free_result']($request); |
||||
766 | |||||
767 | return $data; |
||||
768 | } |
||||
769 | |||||
770 | /** |
||||
771 | * Get the latest topics information from a specific board, |
||||
772 | * to display later. |
||||
773 | * The returned array will be generated to match the xml_format. |
||||
774 | * |
||||
775 | * @todo does not belong here |
||||
776 | * |
||||
777 | * @param string $xml_format The XML format. Can be 'atom', 'rdf', 'rss', 'rss2' or 'smf'. |
||||
778 | * @return array An array of arrays of topic data for the feed. Each array has keys corresponding to the tags for the specified format. |
||||
779 | */ |
||||
780 | function getXmlNews($xml_format) |
||||
781 | { |
||||
782 | global $scripturl, $modSettings, $board, $user_info; |
||||
783 | global $query_this_board, $smcFunc, $context, $txt; |
||||
784 | |||||
785 | /* Find the latest posts that: |
||||
786 | - are the first post in their topic. |
||||
787 | - are on an any board OR in a specified board. |
||||
788 | - can be seen by this user. |
||||
789 | - are actually the latest posts. */ |
||||
790 | |||||
791 | $done = false; |
||||
792 | $loops = 0; |
||||
793 | while (!$done) |
||||
794 | { |
||||
795 | $optimize_msg = implode(' AND ', $context['optimize_msg']); |
||||
796 | $request = $smcFunc['db_query']('', ' |
||||
797 | SELECT |
||||
798 | m.smileys_enabled, m.poster_time, m.id_msg, m.subject, m.body, m.modified_time, |
||||
799 | m.icon, t.id_topic, t.id_board, t.num_replies, |
||||
800 | b.name AS bname, |
||||
801 | COALESCE(mem.id_member, 0) AS id_member, |
||||
802 | COALESCE(mem.email_address, m.poster_email) AS poster_email, |
||||
803 | COALESCE(mem.real_name, m.poster_name) AS poster_name |
||||
804 | FROM {db_prefix}topics AS t |
||||
805 | INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) |
||||
806 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
||||
807 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
||||
808 | WHERE ' . $query_this_board . (empty($optimize_msg) ? '' : ' |
||||
809 | AND {raw:optimize_msg}') . (empty($board) ? '' : ' |
||||
810 | AND t.id_board = {int:current_board}') . ($modSettings['postmod_active'] ? ' |
||||
811 | AND t.approved = {int:is_approved}' : '') . ' |
||||
812 | ORDER BY t.id_first_msg DESC |
||||
813 | LIMIT {int:limit}', |
||||
814 | array( |
||||
815 | 'current_board' => $board, |
||||
816 | 'is_approved' => 1, |
||||
817 | 'limit' => $_GET['limit'], |
||||
818 | 'optimize_msg' => $optimize_msg, |
||||
819 | ) |
||||
820 | ); |
||||
821 | // If we don't have $_GET['limit'] results, try again with an unoptimized version covering all rows. |
||||
822 | if ($loops < 2 && $smcFunc['db_num_rows']($request) < $_GET['limit']) |
||||
823 | { |
||||
824 | $smcFunc['db_free_result']($request); |
||||
825 | if (empty($_REQUEST['boards']) && empty($board)) |
||||
826 | unset($context['optimize_msg']['lowest']); |
||||
827 | else |
||||
828 | $context['optimize_msg']['lowest'] = 'm.id_msg >= t.id_first_msg'; |
||||
829 | $context['optimize_msg']['highest'] = 'm.id_msg <= t.id_last_msg'; |
||||
830 | $loops++; |
||||
831 | } |
||||
832 | else |
||||
833 | $done = true; |
||||
834 | } |
||||
835 | $data = array(); |
||||
836 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
837 | { |
||||
838 | // Limit the length of the message, if the option is set. |
||||
839 | if (!empty($modSettings['xmlnews_maxlen']) && $smcFunc['strlen'](str_replace('<br>', "\n", $row['body'])) > $modSettings['xmlnews_maxlen']) |
||||
840 | $row['body'] = strtr($smcFunc['substr'](str_replace('<br>', "\n", $row['body']), 0, $modSettings['xmlnews_maxlen'] - 3), array("\n" => '<br>')) . '...'; |
||||
841 | |||||
842 | $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']); |
||||
843 | |||||
844 | censorText($row['body']); |
||||
845 | censorText($row['subject']); |
||||
846 | |||||
847 | // Do we want to include any attachments? |
||||
848 | if (!empty($modSettings['attachmentEnable']) && !empty($modSettings['xmlnews_attachments']) && allowedTo('view_attachments', $row['id_board'])) |
||||
849 | { |
||||
850 | $attach_request = $smcFunc['db_query']('', ' |
||||
851 | SELECT |
||||
852 | a.id_attach, a.filename, COALESCE(a.size, 0) AS filesize, a.mime_type, a.downloads, a.approved, m.id_topic AS topic |
||||
853 | FROM {db_prefix}attachments AS a |
||||
854 | LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) |
||||
855 | WHERE a.attachment_type = {int:attachment_type} |
||||
856 | AND a.id_msg = {int:message_id}', |
||||
857 | array( |
||||
858 | 'message_id' => $row['id_msg'], |
||||
859 | 'attachment_type' => 0, |
||||
860 | 'is_approved' => 1, |
||||
861 | ) |
||||
862 | ); |
||||
863 | $loaded_attachments = array(); |
||||
864 | while ($attach = $smcFunc['db_fetch_assoc']($attach_request)) |
||||
865 | { |
||||
866 | // Include approved attachments only |
||||
867 | if ($attach['approved']) |
||||
868 | $loaded_attachments['attachment_' . $attach['id_attach']] = $attach; |
||||
869 | } |
||||
870 | $smcFunc['db_free_result']($attach_request); |
||||
871 | |||||
872 | // Sort the attachments by size to make things easier below |
||||
873 | if (!empty($loaded_attachments)) |
||||
874 | { |
||||
875 | uasort($loaded_attachments, function($a, $b) |
||||
876 | { |
||||
877 | if ($a['filesize'] == $b['filesize']) |
||||
878 | return 0; |
||||
879 | return ($a['filesize'] < $b['filesize']) ? -1 : 1; |
||||
880 | }); |
||||
881 | } |
||||
882 | else |
||||
883 | $loaded_attachments = null; |
||||
884 | } |
||||
885 | else |
||||
886 | $loaded_attachments = null; |
||||
887 | |||||
888 | // Create a GUID for this topic using the tag URI scheme |
||||
889 | $guid = 'tag:' . parse_url($scripturl, PHP_URL_HOST) . ',' . gmdate('Y-m-d', $row['poster_time']) . ':topic=' . $row['id_topic']; |
||||
890 | |||||
891 | // Being news, this actually makes sense in rss format. |
||||
892 | if ($xml_format == 'rss' || $xml_format == 'rss2') |
||||
893 | { |
||||
894 | // Only one attachment allowed in RSS. |
||||
895 | if ($loaded_attachments !== null) |
||||
896 | { |
||||
897 | $attachment = array_pop($loaded_attachments); |
||||
0 ignored issues
–
show
$loaded_attachments of type null is incompatible with the type array expected by parameter $array of array_pop() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
898 | $enclosure = array( |
||||
899 | 'url' => fix_possible_url($scripturl . '?action=dlattach;topic=' . $attachment['topic'] . '.0;attach=' . $attachment['id_attach']), |
||||
900 | 'length' => $attachment['filesize'], |
||||
901 | 'type' => $attachment['mime_type'], |
||||
902 | ); |
||||
903 | } |
||||
904 | else |
||||
905 | $enclosure = null; |
||||
906 | |||||
907 | $data[] = array( |
||||
908 | 'tag' => 'item', |
||||
909 | 'content' => array( |
||||
910 | array( |
||||
911 | 'tag' => 'title', |
||||
912 | 'content' => $row['subject'], |
||||
913 | ), |
||||
914 | array( |
||||
915 | 'tag' => 'link', |
||||
916 | 'content' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
||||
917 | ), |
||||
918 | array( |
||||
919 | 'tag' => 'description', |
||||
920 | 'content' => $row['body'], |
||||
921 | ), |
||||
922 | array( |
||||
923 | 'tag' => 'author', |
||||
924 | 'content' => (allowedTo('moderate_forum') || $row['id_member'] == $user_info['id']) ? $row['poster_email'] . ' (' . $row['poster_name'] . ')' : null, |
||||
925 | ), |
||||
926 | array( |
||||
927 | 'tag' => 'comments', |
||||
928 | 'content' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.0', |
||||
929 | ), |
||||
930 | array( |
||||
931 | 'tag' => 'category', |
||||
932 | 'content' => $row['bname'], |
||||
933 | ), |
||||
934 | array( |
||||
935 | 'tag' => 'pubDate', |
||||
936 | 'content' => gmdate('D, d M Y H:i:s \G\M\T', $row['poster_time']), |
||||
937 | ), |
||||
938 | array( |
||||
939 | 'tag' => 'guid', |
||||
940 | 'content' => $guid, |
||||
941 | 'attributes' => array( |
||||
942 | 'isPermaLink' => 'false', |
||||
943 | ), |
||||
944 | ), |
||||
945 | array( |
||||
946 | 'tag' => 'enclosure', |
||||
947 | 'attributes' => $enclosure, |
||||
948 | ), |
||||
949 | ), |
||||
950 | ); |
||||
951 | } |
||||
952 | elseif ($xml_format == 'rdf') |
||||
953 | { |
||||
954 | $data[] = array( |
||||
955 | 'tag' => 'item', |
||||
956 | 'attributes' => array('rdf:about' => $scripturl . '?topic=' . $row['id_topic'] . '.0'), |
||||
957 | 'content' => array( |
||||
958 | array( |
||||
959 | 'tag' => 'dc:format', |
||||
960 | 'content' => 'text/html', |
||||
961 | ), |
||||
962 | array( |
||||
963 | 'tag' => 'title', |
||||
964 | 'content' => $row['subject'], |
||||
965 | ), |
||||
966 | array( |
||||
967 | 'tag' => 'link', |
||||
968 | 'content' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
||||
969 | ), |
||||
970 | array( |
||||
971 | 'tag' => 'description', |
||||
972 | 'content' => $row['body'], |
||||
973 | ), |
||||
974 | ), |
||||
975 | ); |
||||
976 | } |
||||
977 | elseif ($xml_format == 'atom') |
||||
978 | { |
||||
979 | // Only one attachment allowed |
||||
980 | if (!empty($loaded_attachments)) |
||||
981 | { |
||||
982 | $attachment = array_pop($loaded_attachments); |
||||
983 | $enclosure = array( |
||||
984 | 'rel' => 'enclosure', |
||||
985 | 'href' => fix_possible_url($scripturl . '?action=dlattach;topic=' . $attachment['topic'] . '.0;attach=' . $attachment['id_attach']), |
||||
986 | 'length' => $attachment['filesize'], |
||||
987 | 'type' => $attachment['mime_type'], |
||||
988 | ); |
||||
989 | } |
||||
990 | else |
||||
991 | $enclosure = null; |
||||
992 | |||||
993 | $data[] = array( |
||||
994 | 'tag' => 'entry', |
||||
995 | 'content' => array( |
||||
996 | array( |
||||
997 | 'tag' => 'title', |
||||
998 | 'content' => $row['subject'], |
||||
999 | ), |
||||
1000 | array( |
||||
1001 | 'tag' => 'link', |
||||
1002 | 'attributes' => array( |
||||
1003 | 'rel' => 'alternate', |
||||
1004 | 'type' => 'text/html', |
||||
1005 | 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
||||
1006 | ), |
||||
1007 | ), |
||||
1008 | array( |
||||
1009 | 'tag' => 'summary', |
||||
1010 | 'attributes' => array('type' => 'html'), |
||||
1011 | 'content' => $row['body'], |
||||
1012 | ), |
||||
1013 | array( |
||||
1014 | 'tag' => 'category', |
||||
1015 | 'attributes' => array('term' => $row['bname']), |
||||
1016 | ), |
||||
1017 | array( |
||||
1018 | 'tag' => 'author', |
||||
1019 | 'content' => array( |
||||
1020 | array( |
||||
1021 | 'tag' => 'name', |
||||
1022 | 'content' => $row['poster_name'], |
||||
1023 | ), |
||||
1024 | array( |
||||
1025 | 'tag' => 'email', |
||||
1026 | 'content' => (allowedTo('moderate_forum') || $row['id_member'] == $user_info['id']) ? $row['poster_email'] : null, |
||||
1027 | ), |
||||
1028 | array( |
||||
1029 | 'tag' => 'uri', |
||||
1030 | 'content' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : null, |
||||
1031 | ), |
||||
1032 | ) |
||||
1033 | ), |
||||
1034 | array( |
||||
1035 | 'tag' => 'published', |
||||
1036 | 'content' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['poster_time']), |
||||
1037 | ), |
||||
1038 | array( |
||||
1039 | 'tag' => 'updated', |
||||
1040 | 'content' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', empty($row['modified_time']) ? $row['poster_time'] : $row['modified_time']), |
||||
1041 | ), |
||||
1042 | array( |
||||
1043 | 'tag' => 'id', |
||||
1044 | 'content' => $guid, |
||||
1045 | ), |
||||
1046 | array( |
||||
1047 | 'tag' => 'link', |
||||
1048 | 'attributes' => $enclosure, |
||||
1049 | ), |
||||
1050 | ), |
||||
1051 | ); |
||||
1052 | } |
||||
1053 | // The biggest difference here is more information. |
||||
1054 | else |
||||
1055 | { |
||||
1056 | $attachments = array(); |
||||
1057 | if (!empty($loaded_attachments)) |
||||
1058 | { |
||||
1059 | foreach ($loaded_attachments as $attachment) |
||||
1060 | { |
||||
1061 | $attachments[] = array( |
||||
1062 | 'tag' => 'attachment', |
||||
1063 | 'content' => array( |
||||
1064 | array( |
||||
1065 | 'tag' => 'id', |
||||
1066 | 'content' => $attachment['id_attach'], |
||||
1067 | ), |
||||
1068 | array( |
||||
1069 | 'tag' => 'name', |
||||
1070 | 'content' => preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', $smcFunc['htmlspecialchars']($attachment['filename'])), |
||||
1071 | ), |
||||
1072 | array( |
||||
1073 | 'tag' => 'downloads', |
||||
1074 | 'content' => $attachment['downloads'], |
||||
1075 | ), |
||||
1076 | array( |
||||
1077 | 'tag' => 'size', |
||||
1078 | 'content' => ($attachment['filesize'] < 1024000) ? round($attachment['filesize'] / 1024, 2) . ' ' . $txt['kilobyte'] : round($attachment['filesize'] / 1024 / 1024, 2) . ' ' . $txt['megabyte'], |
||||
1079 | ), |
||||
1080 | array( |
||||
1081 | 'tag' => 'byte_size', |
||||
1082 | 'content' => $attachment['filesize'], |
||||
1083 | ), |
||||
1084 | array( |
||||
1085 | 'tag' => 'link', |
||||
1086 | 'content' => $scripturl . '?action=dlattach;topic=' . $attachment['topic'] . '.0;attach=' . $attachment['id_attach'], |
||||
1087 | ), |
||||
1088 | ) |
||||
1089 | ); |
||||
1090 | } |
||||
1091 | } |
||||
1092 | else |
||||
1093 | $attachments = null; |
||||
1094 | |||||
1095 | $data[] = array( |
||||
1096 | 'tag' => 'article', |
||||
1097 | 'content' => array( |
||||
1098 | array( |
||||
1099 | 'tag' => 'time', |
||||
1100 | 'content' => $smcFunc['htmlspecialchars'](strip_tags(timeformat($row['poster_time']))), |
||||
1101 | ), |
||||
1102 | array( |
||||
1103 | 'tag' => 'id', |
||||
1104 | 'content' => $row['id_topic'], |
||||
1105 | ), |
||||
1106 | array( |
||||
1107 | 'tag' => 'subject', |
||||
1108 | 'content' => $row['subject'], |
||||
1109 | ), |
||||
1110 | array( |
||||
1111 | 'tag' => 'body', |
||||
1112 | 'content' => $row['body'], |
||||
1113 | ), |
||||
1114 | array( |
||||
1115 | 'tag' => 'poster', |
||||
1116 | 'content' => array( |
||||
1117 | array( |
||||
1118 | 'tag' => 'name', |
||||
1119 | 'content' => $row['poster_name'], |
||||
1120 | ), |
||||
1121 | array( |
||||
1122 | 'tag' => 'id', |
||||
1123 | 'content' => $row['id_member'], |
||||
1124 | ), |
||||
1125 | array( |
||||
1126 | 'tag' => 'link', |
||||
1127 | 'content' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : '', |
||||
1128 | ), |
||||
1129 | ) |
||||
1130 | ), |
||||
1131 | array( |
||||
1132 | 'tag' => 'topic', |
||||
1133 | 'content' => $row['id_topic'], |
||||
1134 | ), |
||||
1135 | array( |
||||
1136 | 'tag' => 'board', |
||||
1137 | 'content' => array( |
||||
1138 | array( |
||||
1139 | 'tag' => 'name', |
||||
1140 | 'content' => $row['bname'], |
||||
1141 | ), |
||||
1142 | array( |
||||
1143 | 'tag' => 'id', |
||||
1144 | 'content' => $row['id_board'], |
||||
1145 | ), |
||||
1146 | array( |
||||
1147 | 'tag' => 'link', |
||||
1148 | 'content' => $scripturl . '?board=' . $row['id_board'] . '.0', |
||||
1149 | ), |
||||
1150 | ), |
||||
1151 | ), |
||||
1152 | array( |
||||
1153 | 'tag' => 'link', |
||||
1154 | 'content' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
||||
1155 | ), |
||||
1156 | array( |
||||
1157 | 'tag' => 'attachments', |
||||
1158 | 'content' => $attachments, |
||||
1159 | ), |
||||
1160 | ), |
||||
1161 | ); |
||||
1162 | } |
||||
1163 | } |
||||
1164 | $smcFunc['db_free_result']($request); |
||||
1165 | |||||
1166 | return $data; |
||||
1167 | } |
||||
1168 | |||||
1169 | /** |
||||
1170 | * Get the recent topics to display. |
||||
1171 | * The returned array will be generated to match the xml_format. |
||||
1172 | * |
||||
1173 | * @todo does not belong here. |
||||
1174 | * |
||||
1175 | * @param string $xml_format The XML format. Can be 'atom', 'rdf', 'rss', 'rss2' or 'smf' |
||||
1176 | * @return array An array of arrays containing data for the feed. Each array has keys corresponding to the appropriate tags for the specified format. |
||||
1177 | */ |
||||
1178 | function getXmlRecent($xml_format) |
||||
1179 | { |
||||
1180 | global $scripturl, $modSettings, $board, $txt; |
||||
1181 | global $query_this_board, $smcFunc, $context, $user_info, $sourcedir; |
||||
1182 | |||||
1183 | require_once($sourcedir . '/Subs-Attachments.php'); |
||||
1184 | |||||
1185 | $done = false; |
||||
1186 | $loops = 0; |
||||
1187 | while (!$done) |
||||
1188 | { |
||||
1189 | $optimize_msg = implode(' AND ', $context['optimize_msg']); |
||||
1190 | $request = $smcFunc['db_query']('', ' |
||||
1191 | SELECT m.id_msg |
||||
1192 | FROM {db_prefix}messages AS m |
||||
1193 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) |
||||
1194 | INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) |
||||
1195 | WHERE ' . $query_this_board . (empty($optimize_msg) ? '' : ' |
||||
1196 | AND {raw:optimize_msg}') . (empty($board) ? '' : ' |
||||
1197 | AND m.id_board = {int:current_board}') . ($modSettings['postmod_active'] ? ' |
||||
1198 | AND m.approved = {int:is_approved}' : '') . ' |
||||
1199 | ORDER BY m.id_msg DESC |
||||
1200 | LIMIT {int:limit}', |
||||
1201 | array( |
||||
1202 | 'limit' => $_GET['limit'], |
||||
1203 | 'current_board' => $board, |
||||
1204 | 'is_approved' => 1, |
||||
1205 | 'optimize_msg' => $optimize_msg, |
||||
1206 | ) |
||||
1207 | ); |
||||
1208 | // If we don't have $_GET['limit'] results, try again with an unoptimized version covering all rows. |
||||
1209 | if ($loops < 2 && $smcFunc['db_num_rows']($request) < $_GET['limit']) |
||||
1210 | { |
||||
1211 | $smcFunc['db_free_result']($request); |
||||
1212 | if (empty($_REQUEST['boards']) && empty($board)) |
||||
1213 | unset($context['optimize_msg']['lowest']); |
||||
1214 | else |
||||
1215 | $context['optimize_msg']['lowest'] = $loops ? 'm.id_msg >= t.id_first_msg' : 'm.id_msg >= (t.id_last_msg - t.id_first_msg) / 2'; |
||||
1216 | $loops++; |
||||
1217 | } |
||||
1218 | else |
||||
1219 | $done = true; |
||||
1220 | } |
||||
1221 | $messages = array(); |
||||
1222 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
1223 | $messages[] = $row['id_msg']; |
||||
1224 | $smcFunc['db_free_result']($request); |
||||
1225 | |||||
1226 | if (empty($messages)) |
||||
1227 | return array(); |
||||
1228 | |||||
1229 | // Find the most recent posts this user can see. |
||||
1230 | $request = $smcFunc['db_query']('', ' |
||||
1231 | SELECT |
||||
1232 | m.smileys_enabled, m.poster_time, m.id_msg, m.subject, m.body, m.id_topic, t.id_board, |
||||
1233 | b.name AS bname, t.num_replies, m.id_member, m.icon, mf.id_member AS id_first_member, |
||||
1234 | COALESCE(mem.real_name, m.poster_name) AS poster_name, mf.subject AS first_subject, |
||||
1235 | COALESCE(memf.real_name, mf.poster_name) AS first_poster_name, |
||||
1236 | COALESCE(mem.email_address, m.poster_email) AS poster_email, m.modified_time |
||||
1237 | FROM {db_prefix}messages AS m |
||||
1238 | INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) |
||||
1239 | INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg) |
||||
1240 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
||||
1241 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
||||
1242 | LEFT JOIN {db_prefix}members AS memf ON (memf.id_member = mf.id_member) |
||||
1243 | WHERE m.id_msg IN ({array_int:message_list}) |
||||
1244 | ' . (empty($board) ? '' : 'AND t.id_board = {int:current_board}') . ' |
||||
1245 | ORDER BY m.id_msg DESC |
||||
1246 | LIMIT {int:limit}', |
||||
1247 | array( |
||||
1248 | 'limit' => $_GET['limit'], |
||||
1249 | 'current_board' => $board, |
||||
1250 | 'message_list' => $messages, |
||||
1251 | ) |
||||
1252 | ); |
||||
1253 | $data = array(); |
||||
1254 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||||
1255 | { |
||||
1256 | // Limit the length of the message, if the option is set. |
||||
1257 | if (!empty($modSettings['xmlnews_maxlen']) && $smcFunc['strlen'](str_replace('<br>', "\n", $row['body'])) > $modSettings['xmlnews_maxlen']) |
||||
1258 | $row['body'] = strtr($smcFunc['substr'](str_replace('<br>', "\n", $row['body']), 0, $modSettings['xmlnews_maxlen'] - 3), array("\n" => '<br>')) . '...'; |
||||
1259 | |||||
1260 | $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']); |
||||
1261 | |||||
1262 | censorText($row['body']); |
||||
1263 | censorText($row['subject']); |
||||
1264 | |||||
1265 | // Do we want to include any attachments? |
||||
1266 | if (!empty($modSettings['attachmentEnable']) && !empty($modSettings['xmlnews_attachments']) && allowedTo('view_attachments', $row['id_board'])) |
||||
1267 | { |
||||
1268 | $attach_request = $smcFunc['db_query']('', ' |
||||
1269 | SELECT |
||||
1270 | a.id_attach, a.filename, COALESCE(a.size, 0) AS filesize, a.mime_type, a.downloads, a.approved, m.id_topic AS topic |
||||
1271 | FROM {db_prefix}attachments AS a |
||||
1272 | LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) |
||||
1273 | WHERE a.attachment_type = {int:attachment_type} |
||||
1274 | AND a.id_msg = {int:message_id}', |
||||
1275 | array( |
||||
1276 | 'message_id' => $row['id_msg'], |
||||
1277 | 'attachment_type' => 0, |
||||
1278 | 'is_approved' => 1, |
||||
1279 | ) |
||||
1280 | ); |
||||
1281 | $loaded_attachments = array(); |
||||
1282 | while ($attach = $smcFunc['db_fetch_assoc']($attach_request)) |
||||
1283 | { |
||||
1284 | // Include approved attachments only |
||||
1285 | if ($attach['approved']) |
||||
1286 | $loaded_attachments['attachment_' . $attach['id_attach']] = $attach; |
||||
1287 | } |
||||
1288 | $smcFunc['db_free_result']($attach_request); |
||||
1289 | |||||
1290 | // Sort the attachments by size to make things easier below |
||||
1291 | if (!empty($loaded_attachments)) |
||||
1292 | { |
||||
1293 | uasort($loaded_attachments, function($a, $b) |
||||
1294 | { |
||||
1295 | if ($a['filesize'] == $b['filesize']) |
||||
1296 | return 0; |
||||
1297 | |||||
1298 | return ($a['filesize'] < $b['filesize']) ? -1 : 1; |
||||
1299 | }); |
||||
1300 | } |
||||
1301 | else |
||||
1302 | $loaded_attachments = null; |
||||
1303 | } |
||||
1304 | else |
||||
1305 | $loaded_attachments = null; |
||||
1306 | |||||
1307 | // Create a GUID for this post using the tag URI scheme |
||||
1308 | $guid = 'tag:' . parse_url($scripturl, PHP_URL_HOST) . ',' . gmdate('Y-m-d', $row['poster_time']) . ':msg=' . $row['id_msg']; |
||||
1309 | |||||
1310 | // Doesn't work as well as news, but it kinda does.. |
||||
1311 | if ($xml_format == 'rss' || $xml_format == 'rss2') |
||||
1312 | { |
||||
1313 | // Only one attachment allowed in RSS. |
||||
1314 | if ($loaded_attachments !== null) |
||||
1315 | { |
||||
1316 | $attachment = array_pop($loaded_attachments); |
||||
0 ignored issues
–
show
$loaded_attachments of type null is incompatible with the type array expected by parameter $array of array_pop() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1317 | $enclosure = array( |
||||
1318 | 'url' => fix_possible_url($scripturl . '?action=dlattach;topic=' . $attachment['topic'] . '.0;attach=' . $attachment['id_attach']), |
||||
1319 | 'length' => $attachment['filesize'], |
||||
1320 | 'type' => $attachment['mime_type'], |
||||
1321 | ); |
||||
1322 | } |
||||
1323 | else |
||||
1324 | $enclosure = null; |
||||
1325 | |||||
1326 | $data[] = array( |
||||
1327 | 'tag' => 'item', |
||||
1328 | 'content' => array( |
||||
1329 | array( |
||||
1330 | 'tag' => 'title', |
||||
1331 | 'content' => $row['subject'], |
||||
1332 | ), |
||||
1333 | array( |
||||
1334 | 'tag' => 'link', |
||||
1335 | 'content' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], |
||||
1336 | ), |
||||
1337 | array( |
||||
1338 | 'tag' => 'description', |
||||
1339 | 'content' => $row['body'], |
||||
1340 | ), |
||||
1341 | array( |
||||
1342 | 'tag' => 'author', |
||||
1343 | 'content' => (allowedTo('moderate_forum') || (!empty($row['id_member']) && $row['id_member'] == $user_info['id'])) ? $row['poster_email'] : null, |
||||
1344 | ), |
||||
1345 | array( |
||||
1346 | 'tag' => 'category', |
||||
1347 | 'content' => $row['bname'], |
||||
1348 | ), |
||||
1349 | array( |
||||
1350 | 'tag' => 'comments', |
||||
1351 | 'content' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.0', |
||||
1352 | ), |
||||
1353 | array( |
||||
1354 | 'tag' => 'pubDate', |
||||
1355 | 'content' => gmdate('D, d M Y H:i:s \G\M\T', $row['poster_time']), |
||||
1356 | ), |
||||
1357 | array( |
||||
1358 | 'tag' => 'guid', |
||||
1359 | 'content' => $guid, |
||||
1360 | 'attributes' => array( |
||||
1361 | 'isPermaLink' => 'false', |
||||
1362 | ), |
||||
1363 | ), |
||||
1364 | array( |
||||
1365 | 'tag' => 'enclosure', |
||||
1366 | 'attributes' => $enclosure, |
||||
1367 | ), |
||||
1368 | ), |
||||
1369 | ); |
||||
1370 | } |
||||
1371 | elseif ($xml_format == 'rdf') |
||||
1372 | { |
||||
1373 | $data[] = array( |
||||
1374 | 'tag' => 'item', |
||||
1375 | 'attributes' => array('rdf:about' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']), |
||||
1376 | 'content' => array( |
||||
1377 | array( |
||||
1378 | 'tag' => 'dc:format', |
||||
1379 | 'content' => 'text/html', |
||||
1380 | ), |
||||
1381 | array( |
||||
1382 | 'tag' => 'title', |
||||
1383 | 'content' => $row['subject'], |
||||
1384 | ), |
||||
1385 | array( |
||||
1386 | 'tag' => 'link', |
||||
1387 | 'content' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], |
||||
1388 | ), |
||||
1389 | array( |
||||
1390 | 'tag' => 'description', |
||||
1391 | 'content' => $row['body'], |
||||
1392 | ), |
||||
1393 | ), |
||||
1394 | ); |
||||
1395 | } |
||||
1396 | elseif ($xml_format == 'atom') |
||||
1397 | { |
||||
1398 | // Only one attachment allowed |
||||
1399 | if (!empty($loaded_attachments)) |
||||
1400 | { |
||||
1401 | $attachment = array_pop($loaded_attachments); |
||||
1402 | $enclosure = array( |
||||
1403 | 'rel' => 'enclosure', |
||||
1404 | 'href' => fix_possible_url($scripturl . '?action=dlattach;topic=' . $attachment['topic'] . '.0;attach=' . $attachment['id_attach']), |
||||
1405 | 'length' => $attachment['filesize'], |
||||
1406 | 'type' => $attachment['mime_type'], |
||||
1407 | ); |
||||
1408 | } |
||||
1409 | else |
||||
1410 | $enclosure = null; |
||||
1411 | |||||
1412 | $data[] = array( |
||||
1413 | 'tag' => 'entry', |
||||
1414 | 'content' => array( |
||||
1415 | array( |
||||
1416 | 'tag' => 'title', |
||||
1417 | 'content' => $row['subject'], |
||||
1418 | ), |
||||
1419 | array( |
||||
1420 | 'tag' => 'link', |
||||
1421 | 'attributes' => array( |
||||
1422 | 'rel' => 'alternate', |
||||
1423 | 'type' => 'text/html', |
||||
1424 | 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], |
||||
1425 | ), |
||||
1426 | ), |
||||
1427 | array( |
||||
1428 | 'tag' => 'summary', |
||||
1429 | 'attributes' => array('type' => 'html'), |
||||
1430 | 'content' => $row['body'], |
||||
1431 | ), |
||||
1432 | array( |
||||
1433 | 'tag' => 'category', |
||||
1434 | 'attributes' => array('term' => $row['bname']), |
||||
1435 | ), |
||||
1436 | array( |
||||
1437 | 'tag' => 'author', |
||||
1438 | 'content' => array( |
||||
1439 | array( |
||||
1440 | 'tag' => 'name', |
||||
1441 | 'content' => $row['poster_name'], |
||||
1442 | ), |
||||
1443 | array( |
||||
1444 | 'tag' => 'email', |
||||
1445 | 'content' => (allowedTo('moderate_forum') || (!empty($row['id_member']) && $row['id_member'] == $user_info['id'])) ? $row['poster_email'] : null, |
||||
1446 | ), |
||||
1447 | array( |
||||
1448 | 'tag' => 'uri', |
||||
1449 | 'content' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : null, |
||||
1450 | ), |
||||
1451 | ), |
||||
1452 | ), |
||||
1453 | array( |
||||
1454 | 'tag' => 'published', |
||||
1455 | 'content' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['poster_time']), |
||||
1456 | ), |
||||
1457 | array( |
||||
1458 | 'tag' => 'updated', |
||||
1459 | 'content' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', empty($row['modified_time']) ? $row['poster_time'] : $row['modified_time']), |
||||
1460 | ), |
||||
1461 | array( |
||||
1462 | 'tag' => 'id', |
||||
1463 | 'content' => $guid, |
||||
1464 | ), |
||||
1465 | array( |
||||
1466 | 'tag' => 'link', |
||||
1467 | 'attributes' => $enclosure, |
||||
1468 | ), |
||||
1469 | ), |
||||
1470 | ); |
||||
1471 | } |
||||
1472 | // A lot of information here. Should be enough to please the rss-ers. |
||||
1473 | else |
||||
1474 | { |
||||
1475 | $attachments = array(); |
||||
1476 | if (!empty($loaded_attachments)) |
||||
1477 | { |
||||
1478 | foreach ($loaded_attachments as $attachment) |
||||
1479 | { |
||||
1480 | $attachments[] = array( |
||||
1481 | 'tag' => 'attachment', |
||||
1482 | 'content' => array( |
||||
1483 | array( |
||||
1484 | 'tag' => 'id', |
||||
1485 | 'content' => $attachment['id_attach'], |
||||
1486 | ), |
||||
1487 | array( |
||||
1488 | 'tag' => 'name', |
||||
1489 | 'content' => preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', $smcFunc['htmlspecialchars']($attachment['filename'])), |
||||
1490 | ), |
||||
1491 | array( |
||||
1492 | 'tag' => 'downloads', |
||||
1493 | 'content' => $attachment['downloads'], |
||||
1494 | ), |
||||
1495 | array( |
||||
1496 | 'tag' => 'size', |
||||
1497 | 'content' => ($attachment['filesize'] < 1024000) ? round($attachment['filesize'] / 1024, 2) . ' ' . $txt['kilobyte'] : round($attachment['filesize'] / 1024 / 1024, 2) . ' ' . $txt['megabyte'], |
||||
1498 | ), |
||||
1499 | array( |
||||
1500 | 'tag' => 'byte_size', |
||||
1501 | 'content' => $attachment['filesize'], |
||||
1502 | ), |
||||
1503 | array( |
||||
1504 | 'tag' => 'link', |
||||
1505 | 'content' => $scripturl . '?action=dlattach;topic=' . $attachment['topic'] . '.0;attach=' . $attachment['id_attach'], |
||||
1506 | ), |
||||
1507 | ) |
||||
1508 | ); |
||||
1509 | } |
||||
1510 | } |
||||
1511 | else |
||||
1512 | $attachments = null; |
||||
1513 | |||||
1514 | $data[] = array( |
||||
1515 | 'tag' => 'recent-post', |
||||
1516 | 'content' => array( |
||||
1517 | array( |
||||
1518 | 'tag' => 'time', |
||||
1519 | 'content' => $smcFunc['htmlspecialchars'](strip_tags(timeformat($row['poster_time']))), |
||||
1520 | ), |
||||
1521 | array( |
||||
1522 | 'tag' => 'id', |
||||
1523 | 'content' => $row['id_msg'], |
||||
1524 | ), |
||||
1525 | array( |
||||
1526 | 'tag' => 'subject', |
||||
1527 | 'content' => $row['subject'], |
||||
1528 | ), |
||||
1529 | array( |
||||
1530 | 'tag' => 'body', |
||||
1531 | 'content' => $row['body'], |
||||
1532 | ), |
||||
1533 | array( |
||||
1534 | 'tag' => 'starter', |
||||
1535 | 'content' => array( |
||||
1536 | array( |
||||
1537 | 'tag' => 'name', |
||||
1538 | 'content' => $row['first_poster_name'], |
||||
1539 | ), |
||||
1540 | array( |
||||
1541 | 'tag' => 'id', |
||||
1542 | 'content' => $row['id_first_member'], |
||||
1543 | ), |
||||
1544 | array( |
||||
1545 | 'tag' => 'link', |
||||
1546 | 'content' => !empty($row['id_first_member']) ? $scripturl . '?action=profile;u=' . $row['id_first_member'] : '', |
||||
1547 | ), |
||||
1548 | ), |
||||
1549 | ), |
||||
1550 | array( |
||||
1551 | 'tag' => 'poster', |
||||
1552 | 'content' => array( |
||||
1553 | array( |
||||
1554 | 'tag' => 'name', |
||||
1555 | 'content' => $row['poster_name'], |
||||
1556 | ), |
||||
1557 | array( |
||||
1558 | 'tag' => 'id', |
||||
1559 | 'content' => $row['id_member'], |
||||
1560 | ), |
||||
1561 | array( |
||||
1562 | 'tag' => 'link', |
||||
1563 | 'content' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : '', |
||||
1564 | ), |
||||
1565 | ), |
||||
1566 | ), |
||||
1567 | array( |
||||
1568 | 'tag' => 'topic', |
||||
1569 | 'content' => array( |
||||
1570 | array( |
||||
1571 | 'tag' => 'subject', |
||||
1572 | 'content' => $row['first_subject'], |
||||
1573 | ), |
||||
1574 | array( |
||||
1575 | 'tag' => 'id', |
||||
1576 | 'content' => $row['id_topic'], |
||||
1577 | ), |
||||
1578 | array( |
||||
1579 | 'tag' => 'link', |
||||
1580 | 'content' => $scripturl . '?topic=' . $row['id_topic'] . '.new#new', |
||||
1581 | ), |
||||
1582 | ), |
||||
1583 | ), |
||||
1584 | array( |
||||
1585 | 'tag' => 'board', |
||||
1586 | 'content' => array( |
||||
1587 | array( |
||||
1588 | 'tag' => 'name', |
||||
1589 | 'content' => $row['bname'], |
||||
1590 | ), |
||||
1591 | array( |
||||
1592 | 'tag' => 'id', |
||||
1593 | 'content' => $row['id_board'], |
||||
1594 | ), |
||||
1595 | array( |
||||
1596 | 'tag' => 'link', |
||||
1597 | 'content' => $scripturl . '?board=' . $row['id_board'] . '.0', |
||||
1598 | ), |
||||
1599 | ), |
||||
1600 | ), |
||||
1601 | array( |
||||
1602 | 'tag' => 'link', |
||||
1603 | 'content' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], |
||||
1604 | ), |
||||
1605 | array( |
||||
1606 | 'tag' => 'attachments', |
||||
1607 | 'content' => $attachments, |
||||
1608 | ), |
||||
1609 | ), |
||||
1610 | ); |
||||
1611 | } |
||||
1612 | } |
||||
1613 | $smcFunc['db_free_result']($request); |
||||
1614 | |||||
1615 | return $data; |
||||
1616 | } |
||||
1617 | |||||
1618 | /** |
||||
1619 | * Get the profile information for member into an array, |
||||
1620 | * which will be generated to match the xml_format. |
||||
1621 | * |
||||
1622 | * @todo refactor. |
||||
1623 | * |
||||
1624 | * @param string $xml_format The XML format. Can be 'atom', 'rdf', 'rss', 'rss2' or 'smf' |
||||
1625 | * @return array An array profile data |
||||
1626 | */ |
||||
1627 | function getXmlProfile($xml_format) |
||||
1628 | { |
||||
1629 | global $scripturl, $memberContext, $user_profile, $user_info; |
||||
1630 | |||||
1631 | // You must input a valid user.... |
||||
1632 | if (empty($_GET['u']) || !loadMemberData((int) $_GET['u'])) |
||||
1633 | return array(); |
||||
1634 | |||||
1635 | // Make sure the id is a number and not "I like trying to hack the database". |
||||
1636 | $_GET['u'] = (int) $_GET['u']; |
||||
1637 | // Load the member's contextual information! |
||||
1638 | if (!loadMemberContext($_GET['u']) || !allowedTo('profile_view')) |
||||
1639 | return array(); |
||||
1640 | |||||
1641 | // Okay, I admit it, I'm lazy. Stupid $_GET['u'] is long and hard to type. |
||||
1642 | $profile = &$memberContext[$_GET['u']]; |
||||
1643 | |||||
1644 | // Create a GUID for this member using the tag URI scheme |
||||
1645 | $guid = 'tag:' . parse_url($scripturl, PHP_URL_HOST) . ',' . gmdate('Y-m-d', $user_profile[$profile['id']]['date_registered']) . ':member=' . $profile['id']; |
||||
1646 | |||||
1647 | if ($xml_format == 'rss' || $xml_format == 'rss2') |
||||
1648 | { |
||||
1649 | $data[] = array( |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
1650 | 'tag' => 'item', |
||||
1651 | 'content' => array( |
||||
1652 | array( |
||||
1653 | 'tag' => 'title', |
||||
1654 | 'content' => $profile['name'], |
||||
1655 | ), |
||||
1656 | array( |
||||
1657 | 'tag' => 'link', |
||||
1658 | 'content' => $scripturl . '?action=profile;u=' . $profile['id'], |
||||
1659 | ), |
||||
1660 | array( |
||||
1661 | 'tag' => 'description', |
||||
1662 | 'content' => isset($profile['group']) ? $profile['group'] : $profile['post_group'], |
||||
1663 | ), |
||||
1664 | array( |
||||
1665 | 'tag' => 'comments', |
||||
1666 | 'content' => $scripturl . '?action=pm;sa=send;u=' . $profile['id'], |
||||
1667 | ), |
||||
1668 | array( |
||||
1669 | 'tag' => 'pubDate', |
||||
1670 | 'content' => gmdate('D, d M Y H:i:s \G\M\T', $user_profile[$profile['id']]['date_registered']), |
||||
1671 | ), |
||||
1672 | array( |
||||
1673 | 'tag' => 'guid', |
||||
1674 | 'content' => $guid, |
||||
1675 | 'attributes' => array( |
||||
1676 | 'isPermaLink' => 'false', |
||||
1677 | ), |
||||
1678 | ), |
||||
1679 | ) |
||||
1680 | ); |
||||
1681 | } |
||||
1682 | elseif ($xml_format == 'rdf') |
||||
1683 | { |
||||
1684 | $data[] = array( |
||||
1685 | 'tag' => 'item', |
||||
1686 | 'attributes' => array('rdf:about' => $scripturl . '?action=profile;u=' . $profile['id']), |
||||
1687 | 'content' => array( |
||||
1688 | array( |
||||
1689 | 'tag' => 'dc:format', |
||||
1690 | 'content' => 'text/html', |
||||
1691 | ), |
||||
1692 | array( |
||||
1693 | 'tag' => 'title', |
||||
1694 | 'content' => $profile['name'], |
||||
1695 | ), |
||||
1696 | array( |
||||
1697 | 'tag' => 'link', |
||||
1698 | 'content' => $scripturl . '?action=profile;u=' . $profile['id'], |
||||
1699 | ), |
||||
1700 | array( |
||||
1701 | 'tag' => 'description', |
||||
1702 | 'content' => isset($profile['group']) ? $profile['group'] : $profile['post_group'], |
||||
1703 | ), |
||||
1704 | ) |
||||
1705 | ); |
||||
1706 | } |
||||
1707 | elseif ($xml_format == 'atom') |
||||
1708 | { |
||||
1709 | $data[] = array( |
||||
1710 | 'tag' => 'entry', |
||||
1711 | 'content' => array( |
||||
1712 | array( |
||||
1713 | 'tag' => 'title', |
||||
1714 | 'content' => $profile['name'], |
||||
1715 | ), |
||||
1716 | array( |
||||
1717 | 'tag' => 'link', |
||||
1718 | 'attributes' => array( |
||||
1719 | 'rel' => 'alternate', |
||||
1720 | 'type' => 'text/html', |
||||
1721 | 'href' => $scripturl . '?action=profile;u=' . $profile['id'], |
||||
1722 | ), |
||||
1723 | ), |
||||
1724 | array( |
||||
1725 | 'tag' => 'summary', |
||||
1726 | 'attributes' => array('type' => 'html'), |
||||
1727 | 'content' => isset($profile['group']) ? $profile['group'] : $profile['post_group'], |
||||
1728 | ), |
||||
1729 | array( |
||||
1730 | 'tag' => 'author', |
||||
1731 | 'content' => array( |
||||
1732 | array( |
||||
1733 | 'tag' => 'name', |
||||
1734 | 'content' => $profile['name'], |
||||
1735 | ), |
||||
1736 | array( |
||||
1737 | 'tag' => 'email', |
||||
1738 | 'content' => $profile['show_email'] ? $profile['email'] : null, |
||||
1739 | ), |
||||
1740 | array( |
||||
1741 | 'tag' => 'uri', |
||||
1742 | 'content' => !empty($profile['website']['url']) ? $profile['website']['url'] : null, |
||||
1743 | ), |
||||
1744 | ), |
||||
1745 | ), |
||||
1746 | array( |
||||
1747 | 'tag' => 'published', |
||||
1748 | 'content' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $user_profile[$profile['id']]['date_registered']), |
||||
1749 | ), |
||||
1750 | array( |
||||
1751 | 'tag' => 'updated', |
||||
1752 | 'content' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $user_profile[$profile['id']]['last_login']), |
||||
1753 | ), |
||||
1754 | array( |
||||
1755 | 'tag' => 'id', |
||||
1756 | 'content' => $guid, |
||||
1757 | ), |
||||
1758 | ) |
||||
1759 | ); |
||||
1760 | } |
||||
1761 | else |
||||
1762 | { |
||||
1763 | $data = array( |
||||
1764 | array( |
||||
1765 | 'tag' => 'username', |
||||
1766 | 'content' => $user_info['is_admin'] || $user_info['id'] == $profile['id'] ? $profile['username'] : null, |
||||
1767 | ), |
||||
1768 | array( |
||||
1769 | 'tag' => 'name', |
||||
1770 | 'content' => $profile['name'], |
||||
1771 | ), |
||||
1772 | array( |
||||
1773 | 'tag' => 'link', |
||||
1774 | 'content' => $scripturl . '?action=profile;u=' . $profile['id'], |
||||
1775 | ), |
||||
1776 | array( |
||||
1777 | 'tag' => 'posts', |
||||
1778 | 'content' => $profile['posts'], |
||||
1779 | ), |
||||
1780 | array( |
||||
1781 | 'tag' => 'post-group', |
||||
1782 | 'content' => $profile['post_group'], |
||||
1783 | ), |
||||
1784 | array( |
||||
1785 | 'tag' => 'language', |
||||
1786 | 'content' => $profile['language'], |
||||
1787 | ), |
||||
1788 | array( |
||||
1789 | 'tag' => 'last-login', |
||||
1790 | 'content' => gmdate('D, d M Y H:i:s \G\M\T', $user_profile[$profile['id']]['last_login']), |
||||
1791 | ), |
||||
1792 | array( |
||||
1793 | 'tag' => 'registered', |
||||
1794 | 'content' => gmdate('D, d M Y H:i:s \G\M\T', $user_profile[$profile['id']]['date_registered']), |
||||
1795 | ), |
||||
1796 | array( |
||||
1797 | 'tag' => 'gender', |
||||
1798 | 'content' => !empty($profile['gender']['name']) ? $profile['gender']['name'] : null, |
||||
1799 | ), |
||||
1800 | array( |
||||
1801 | 'tag' => 'avatar', |
||||
1802 | 'content' => !empty($profile['avatar']['url']) ? $profile['avatar']['url'] : null, |
||||
1803 | ), |
||||
1804 | array( |
||||
1805 | 'tag' => 'online', |
||||
1806 | 'content' => !empty($profile['online']['is_online']) ? '' : null, |
||||
1807 | ), |
||||
1808 | array( |
||||
1809 | 'tag' => 'signature', |
||||
1810 | 'content' => !empty($profile['signature']) ? $profile['signature'] : null, |
||||
1811 | ), |
||||
1812 | array( |
||||
1813 | 'tag' => 'blurb', |
||||
1814 | 'content' => !empty($profile['blurb']) ? $profile['blurb'] : null, |
||||
1815 | ), |
||||
1816 | array( |
||||
1817 | 'tag' => 'title', |
||||
1818 | 'content' => !empty($profile['title']) ? $profile['title'] : null, |
||||
1819 | ), |
||||
1820 | array( |
||||
1821 | 'tag' => 'position', |
||||
1822 | 'content' => !empty($profile['group']) ? $profile['group'] : null, |
||||
1823 | ), |
||||
1824 | array( |
||||
1825 | 'tag' => 'email', |
||||
1826 | 'content' => !empty($profile['show_email']) ? $profile['show_email'] : null, |
||||
1827 | ), |
||||
1828 | array( |
||||
1829 | 'tag' => 'website', |
||||
1830 | 'content' => empty($profile['website']['url']) ? null : array( |
||||
1831 | array( |
||||
1832 | 'tag' => 'title', |
||||
1833 | 'content' => !empty($profile['website']['title']) ? $profile['website']['title'] : null, |
||||
1834 | ), |
||||
1835 | array( |
||||
1836 | 'tag' => 'link', |
||||
1837 | 'content' => $profile['website']['url'], |
||||
1838 | ), |
||||
1839 | ), |
||||
1840 | ), |
||||
1841 | ); |
||||
1842 | |||||
1843 | if (!empty($profile['birth_date']) && substr($profile['birth_date'], 0, 4) != '0000') |
||||
1844 | { |
||||
1845 | list ($birth_year, $birth_month, $birth_day) = sscanf($profile['birth_date'], '%d-%d-%d'); |
||||
1846 | $datearray = getdate(forum_time()); |
||||
1847 | $age = $datearray['year'] - $birth_year - (($datearray['mon'] > $birth_month || ($datearray['mon'] == $birth_month && $datearray['mday'] >= $birth_day)) ? 0 : 1); |
||||
1848 | |||||
1849 | $data[] = array( |
||||
1850 | 'tag' => 'age', |
||||
1851 | 'content' => $age, |
||||
1852 | ); |
||||
1853 | } |
||||
1854 | } |
||||
1855 | |||||
1856 | // Save some memory. |
||||
1857 | unset($profile, $memberContext[$_GET['u']]); |
||||
1858 | |||||
1859 | return $data; |
||||
1860 | } |
||||
1861 | |||||
1862 | ?> |