Esempio n. 1
0
function dumpTags($data, $i, $tag = null, $xml_format = '')
{
    global $modSettings, $context, $scripturl;
    // For every array in the data...
    foreach ($data as $key => $val) {
        // Skip it, it's been set to null.
        if ($val == null) {
            continue;
        }
        // If a tag was passed, use it instead of the key.
        $key = isset($tag) ? $tag : $key;
        // First let's indent!
        echo "\n", str_repeat("\t", $i);
        // Grr, I hate kludges... almost worth doing it properly, here, but not quite.
        if ($xml_format == 'atom' && $key == 'link') {
            echo '<link rel="alternate" type="text/html" href="', fix_possible_url($val), '" />';
            continue;
        }
        // If it's empty/0/nothing simply output an empty tag.
        if ($val == '') {
            echo '<', $key, ' />';
        } else {
            // Beginning tag.
            if ($xml_format == 'rdf' && $key == 'item' && isset($val['link'])) {
                echo '<', $key, ' rdf:about="', fix_possible_url($val['link']), '">';
                echo "\n", str_repeat("\t", $i + 1);
                echo '<dc:format>text/html</dc:format>';
            } elseif ($xml_format == 'atom' && $key == 'summary') {
                echo '<', $key, ' type="html">';
            } else {
                echo '<', $key, '>';
            }
            if (is_array($val)) {
                // An array.  Dump it, and then indent the tag.
                dumpTags($val, $i + 1, null, $xml_format);
                echo "\n", str_repeat("\t", $i), '</', $key, '>';
            } elseif (strpos($val, "\n") !== false || strpos($val, '<br />') !== false) {
                echo "\n", fix_possible_url($val), "\n", str_repeat("\t", $i), '</', $key, '>';
            } else {
                echo fix_possible_url($val), '</', $key, '>';
            }
        }
    }
}
Esempio n. 2
0
    /**
     * Outputs xml data representing recent information or a profile.
     *
     * What it does:
     * - Can be passed 4 subactions which decide what is output:
     *   'recent' for recent posts,
     *   'news' for news topics,
     *   'members' for recently registered members,
     *   'profile' for a member's profile.
     * - To display a member's profile, a user id has to be given. (;u=1) e.g. ?action=.xml;sa=profile;u=1;type=atom
     * - Outputs an rss feed instead of a proprietary one if the 'type' $_GET
     * parameter is 'rss' or 'rss2'.
     * - Accessed via ?action=.xml
     * - Does not use any templates, sub templates, or template layers.
     *
     * @uses Stats language file.
     */
    public function action_showfeed()
    {
        global $board, $board_info, $context, $scripturl, $boardurl, $txt, $modSettings, $user_info;
        global $forum_version, $cdata_override, $settings;
        // If it's not enabled, die.
        if (empty($modSettings['xmlnews_enable'])) {
            obExit(false);
        }
        loadLanguage('Stats');
        $txt['xml_rss_desc'] = replaceBasicActionUrl($txt['xml_rss_desc']);
        // Default to latest 5.  No more than whats defined in the ACP or 255
        $limit = empty($modSettings['xmlnews_limit']) ? 5 : min($modSettings['xmlnews_limit'], 255);
        $this->_limit = empty($_GET['limit']) || (int) $_GET['limit'] < 1 ? $limit : min((int) $_GET['limit'], $limit);
        // Handle the cases where a board, boards, or category is asked for.
        $this->_query_this_board = '1=1';
        $context['optimize_msg'] = array('highest' => 'm.id_msg <= b.id_last_msg');
        if (!empty($_REQUEST['c']) && empty($board)) {
            $categories = array_map('intval', explode(',', $_REQUEST['c']));
            if (count($categories) == 1) {
                require_once SUBSDIR . '/Categories.subs.php';
                $feed_title = categoryName($categories[0]);
                $feed_title = ' - ' . strip_tags($feed_title);
            }
            require_once SUBSDIR . '/Boards.subs.php';
            $boards_posts = boardsPosts(array(), $categories);
            $total_cat_posts = array_sum($boards_posts);
            $boards = array_keys($boards_posts);
            if (!empty($boards)) {
                $this->_query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')';
            }
            // Try to limit the number of messages we look through.
            if ($total_cat_posts > 100 && $total_cat_posts > $modSettings['totalMessages'] / 15) {
                $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 400 - $this->_limit * 5);
            }
        } elseif (!empty($_REQUEST['boards'])) {
            require_once SUBSDIR . '/Boards.subs.php';
            $query_boards = array_map('intval', explode(',', $_REQUEST['boards']));
            $boards_data = fetchBoardsInfo(array('boards' => $query_boards), array('selects' => 'detailed'));
            // Either the board specified doesn't exist or you have no access.
            $num_boards = count($boards_data);
            if ($num_boards == 0) {
                fatal_lang_error('no_board');
            }
            $total_posts = 0;
            $boards = array_keys($boards_data);
            foreach ($boards_data as $row) {
                if ($num_boards == 1) {
                    $feed_title = ' - ' . strip_tags($row['name']);
                }
                $total_posts += $row['num_posts'];
            }
            $this->_query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')';
            // The more boards, the more we're going to look through...
            if ($total_posts > 100 && $total_posts > $modSettings['totalMessages'] / 12) {
                $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 500 - $this->_limit * 5);
            }
        } elseif (!empty($board)) {
            require_once SUBSDIR . '/Boards.subs.php';
            $boards_data = fetchBoardsInfo(array('boards' => $board), array('selects' => 'posts'));
            $feed_title = ' - ' . strip_tags($board_info['name']);
            $this->_query_this_board = 'b.id_board = ' . $board;
            // Try to look through just a few messages, if at all possible.
            if ($boards_data[$board]['num_posts'] > 80 && $boards_data[$board]['num_posts'] > $modSettings['totalMessages'] / 10) {
                $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 600 - $this->_limit * 5);
            }
        } else {
            $this->_query_this_board = '{query_see_board}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
				AND b.id_board != ' . $modSettings['recycle_board'] : '');
            $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 100 - $this->_limit * 5);
        }
        // If format isn't set, rss2 is default
        $xml_format = isset($_GET['type']) && in_array($_GET['type'], array('rss', 'rss2', 'atom', 'rdf', 'webslice')) ? $_GET['type'] : 'rss2';
        // List all the different types of data they can pull.
        $subActions = array('recent' => array('action_xmlrecent'), 'news' => array('action_xmlnews'), 'members' => array('action_xmlmembers'), 'profile' => array('action_xmlprofile'));
        // Easy adding of sub actions
        call_integration_hook('integrate_xmlfeeds', array(&$subActions));
        $subAction = isset($_GET['sa']) && isset($subActions[$_GET['sa']]) ? $_GET['sa'] : 'recent';
        // Webslices doesn't do everything (yet? ever?) so for now only recent posts is allowed in that format
        if ($xml_format == 'webslice' && $subAction != 'recent') {
            $xml_format = 'rss2';
        } elseif ($xml_format == 'webslice') {
            $context['user'] += $user_info;
            $cdata_override = true;
            loadTemplate('Xml');
        }
        // We only want some information, not all of it.
        $cachekey = array($xml_format, $_GET['action'], $this->_limit, $subAction);
        foreach (array('board', 'boards', 'c') as $var) {
            if (isset($_REQUEST[$var])) {
                $cachekey[] = $_REQUEST[$var];
            }
        }
        $cachekey = md5(serialize($cachekey) . (!empty($this->_query_this_board) ? $this->_query_this_board : ''));
        $cache_t = microtime(true);
        // Get the associative array representing the xml.
        if (!empty($modSettings['cache_enable']) && (!$user_info['is_guest'] || $modSettings['cache_enable'] >= 3)) {
            $xml = cache_get_data('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, 240);
        }
        if (empty($xml)) {
            $xml = $this->{$subActions[$subAction][0]}($xml_format);
            if (!empty($modSettings['cache_enable']) && ($user_info['is_guest'] && $modSettings['cache_enable'] >= 3 || !$user_info['is_guest'] && microtime(true) - $cache_t > 0.2)) {
                cache_put_data('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, $xml, 240);
            }
        }
        $feed_title = encode_special(strip_tags(un_htmlspecialchars($context['forum_name']) . (isset($feed_title) ? $feed_title : '')));
        // This is an xml file....
        @ob_end_clean();
        if (!empty($modSettings['enableCompressedOutput'])) {
            ob_start('ob_gzhandler');
        } else {
            ob_start();
        }
        if (isset($_REQUEST['debug'])) {
            header('Content-Type: text/xml; charset=UTF-8');
        } elseif ($xml_format == 'rss' || $xml_format == 'rss2' || $xml_format == 'webslice') {
            header('Content-Type: application/rss+xml; charset=UTF-8');
        } elseif ($xml_format == 'atom') {
            header('Content-Type: application/atom+xml; charset=UTF-8');
        } elseif ($xml_format == 'rdf') {
            header('Content-Type: ' . (isBrowser('ie') ? 'text/xml' : 'application/rdf+xml') . '; charset=UTF-8');
        }
        // First, output the xml header.
        echo '<?xml version="1.0" encoding="UTF-8"?' . '>';
        // Are we outputting an rss feed or one with more information?
        if ($xml_format == 'rss' || $xml_format == 'rss2') {
            // Start with an RSS 2.0 header.
            echo '
	<rss version=', $xml_format == 'rss2' ? '"2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"' : '"0.92"', ' xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">
		<channel>
			<title>', $feed_title, '</title>
			<link>', $scripturl, '</link>
			<description><![CDATA[', un_htmlspecialchars(strip_tags($txt['xml_rss_desc'])), ']]></description>
			<generator>ElkArte</generator>
			<ttl>30</ttl>
			<image>
				<url>', $settings['default_theme_url'], '/images/logo.png</url>
				<title>', $feed_title, '</title>
				<link>', $scripturl, '</link>
			</image>';
            // Output all of the associative array, start indenting with 2 tabs, and name everything "item".
            dumpTags($xml, 2, 'item', $xml_format);
            // Output the footer of the xml.
            echo '
		</channel>
	</rss>';
        } elseif ($xml_format == 'webslice') {
            // Format specification http://msdn.microsoft.com/en-us/library/cc304073%28VS.85%29.aspx
            // Known browsers to support webslices: IE8, IE9, Firefox with Webchunks addon.
            // It uses RSS 2.
            // We send a feed with recent posts, and alerts for PMs for logged in users
            $context['recent_posts_data'] = $xml;
            $context['can_pm_read'] = allowedTo('pm_read');
            // This always has RSS 2
            echo '
	<rss version="2.0" xmlns:mon="http://www.microsoft.com/schemas/rss/monitoring/2007" xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">
		<channel>
			<title>', $feed_title, ' - ', $txt['recent_posts'], '</title>
			<link>', $scripturl, '?action=recent</link>
			<description><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></description>
			<item>
				<title>', $feed_title, ' - ', $txt['recent_posts'], '</title>
				<link>', $scripturl, '?action=recent</link>
				<description><![CDATA[
					', template_webslice_header_above(), '
					', template_webslice_recent_posts(), '
				]]></description>
			</item>
		</channel>
	</rss>';
        } elseif ($xml_format == 'atom') {
            $url_parts = array();
            foreach (array('board', 'boards', 'c') as $var) {
                if (isset($_REQUEST[$var])) {
                    $url_parts[] = $var . '=' . (is_array($_REQUEST[$var]) ? implode(',', $_REQUEST[$var]) : $_REQUEST[$var]);
                }
            }
            echo '
	<feed xmlns="http://www.w3.org/2005/Atom">
		<title>', $feed_title, '</title>
		<link rel="alternate" type="text/html" href="', $scripturl, '" />
		<link rel="self" type="application/rss+xml" href="', $scripturl, '?type=atom;action=.xml', !empty($url_parts) ? ';' . implode(';', $url_parts) : '', '" />
		<id>', $scripturl, '</id>
		<icon>', $boardurl, '/favicon.ico</icon>

		<updated>', gmstrftime('%Y-%m-%dT%H:%M:%SZ'), '</updated>
		<subtitle><![CDATA[', strip_tags(un_htmlspecialchars($txt['xml_rss_desc'])), ']]></subtitle>
		<generator uri="http://www.elkarte.net" version="', strtr($forum_version, array('ElkArte' => '')), '">ElkArte</generator>
		<author>
			<name>', strip_tags(un_htmlspecialchars($context['forum_name'])), '</name>
		</author>';
            dumpTags($xml, 2, 'entry', $xml_format);
            echo '
	</feed>';
        } else {
            echo '
	<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/">
		<channel rdf:about="', $scripturl, '">
			<title>', $feed_title, '</title>
			<link>', $scripturl, '</link>
			<description><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></description>
			<items>
				<rdf:Seq>';
            foreach ($xml as $item) {
                echo '
					<rdf:li rdf:resource="', $item['link'], '" />';
            }
            echo '
				</rdf:Seq>
			</items>
		</channel>
	';
            dumpTags($xml, 1, 'item', $xml_format);
            echo '
	</rdf:RDF>';
        }
        obExit(false);
    }