Exemple #1
0
function ShowXmlFeed()
{
    global $board, $board_info, $context, $scripturl, $txt, $modSettings, $user_info;
    global $query_this_board, $smcFunc, $forum_version, $cdata_override;
    // If it's not enabled, die.
    if (empty($modSettings['xmlnews_enable'])) {
        obExit(false);
    }
    loadLanguage('Stats');
    // Default to latest 5.  No more than 255, please.
    $_GET['limit'] = empty($_GET['limit']) || (int) $_GET['limit'] < 1 ? 5 : min((int) $_GET['limit'], 255);
    // Handle the cases where a board, boards, or category is asked for.
    $query_this_board = 1;
    $context['optimize_msg'] = array('highest' => 'm.id_msg <= b.id_last_msg');
    if (!empty($_REQUEST['c']) && empty($board)) {
        $_REQUEST['c'] = explode(',', $_REQUEST['c']);
        foreach ($_REQUEST['c'] as $i => $c) {
            $_REQUEST['c'][$i] = (int) $c;
        }
        if (count($_REQUEST['c']) == 1) {
            $request = smf_db_query('
				SELECT name
				FROM {db_prefix}categories
				WHERE id_cat = {int:current_category}', array('current_category' => (int) $_REQUEST['c'][0]));
            list($feed_title) = mysql_fetch_row($request);
            mysql_free_result($request);
            $feed_title = ' - ' . strip_tags($feed_title);
        }
        $request = smf_db_query('
			SELECT b.id_board, b.num_posts
			FROM {db_prefix}boards AS b
			WHERE b.id_cat IN ({array_int:current_category_list})
				AND {query_see_board}', array('current_category_list' => $_REQUEST['c']));
        $total_cat_posts = 0;
        $boards = array();
        while ($row = mysql_fetch_assoc($request)) {
            $boards[] = $row['id_board'];
            $total_cat_posts += $row['num_posts'];
        }
        mysql_free_result($request);
        if (!empty($boards)) {
            $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 - $_GET['limit'] * 5);
        }
    } elseif (!empty($_REQUEST['boards'])) {
        $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
        foreach ($_REQUEST['boards'] as $i => $b) {
            $_REQUEST['boards'][$i] = (int) $b;
        }
        $request = smf_db_query('
			SELECT b.id_board, b.num_posts, b.name
			FROM {db_prefix}boards AS b
			WHERE b.id_board IN ({array_int:board_list})
				AND {query_see_board}
			LIMIT ' . count($_REQUEST['boards']), array('board_list' => $_REQUEST['boards']));
        // Either the board specified doesn't exist or you have no access.
        $num_boards = mysql_num_rows($request);
        if ($num_boards == 0) {
            fatal_lang_error('no_board');
        }
        $total_posts = 0;
        $boards = array();
        while ($row = mysql_fetch_assoc($request)) {
            if ($num_boards == 1) {
                $feed_title = ' - ' . strip_tags($row['name']);
            }
            $boards[] = $row['id_board'];
            $total_posts += $row['num_posts'];
        }
        mysql_free_result($request);
        if (!empty($boards)) {
            $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 - $_GET['limit'] * 5);
        }
    } elseif (!empty($board)) {
        $request = smf_db_query('
			SELECT num_posts
			FROM {db_prefix}boards
			WHERE id_board = {int:current_board}
			LIMIT 1', array('current_board' => $board));
        list($total_posts) = mysql_fetch_row($request);
        mysql_free_result($request);
        $feed_title = ' - ' . strip_tags($board_info['name']);
        $query_this_board = 'b.id_board = ' . $board;
        // Try to look through just a few messages, if at all possible.
        if ($total_posts > 80 && $total_posts > $modSettings['totalMessages'] / 10) {
            $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 600 - $_GET['limit'] * 5);
        }
    } else {
        $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 - $_GET['limit'] * 5);
    }
    // Show in rss or proprietary format?
    $xml_format = isset($_GET['type']) && in_array($_GET['type'], array('smf', 'rss', 'rss2', 'atom', 'rdf', 'webslice')) ? $_GET['type'] : 'smf';
    // !!! Birthdays?
    // List all the different types of data they can pull.
    $subActions = array('recent' => array('getXmlRecent', 'recent-post'), 'news' => array('getXmlNews', 'article'), 'members' => array('getXmlMembers', 'member'), 'profile' => array('getXmlProfile', null));
    if (empty($_GET['sa']) || !isset($subActions[$_GET['sa']])) {
        $_GET['sa'] = 'recent';
    }
    //!!! Temp - webslices doesn't do everything yet.
    if ($xml_format == 'webslice' && $_GET['sa'] != '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'], $_GET['limit'], $_GET['sa']);
    foreach (array('board', 'boards', 'c') as $var) {
        if (isset($_REQUEST[$var])) {
            $cachekey[] = $_REQUEST[$var];
        }
    }
    $cachekey = md5(serialize($cachekey) . (!empty($query_this_board) ? $query_this_board : ''));
    $cache_t = microtime();
    // Get the associative array representing the xml.
    if (!empty($modSettings['cache_enable']) && (!$user_info['is_guest'] || $modSettings['cache_enable'] >= 3)) {
        $xml = CacheAPI::getCache('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, 240);
    }
    if (empty($xml)) {
        $xml = $subActions[$_GET['sa']][0]($xml_format);
        if (!empty($modSettings['cache_enable']) && ($user_info['is_guest'] && $modSettings['cache_enable'] >= 3 || !$user_info['is_guest'] && array_sum(explode(' ', microtime())) - array_sum(explode(' ', $cache_t)) > 0.2)) {
            CacheAPI::putCache('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, $xml, 240);
        }
    }
    $feed_title = htmlspecialchars(strip_tags($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 ($xml_format == 'smf' || 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: ' . ($context['browser']['is_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"' : '"0.92"', ' xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">
	<channel>
		<title>', $feed_title, '</title>
		<link>', $scripturl, '</link>
		<description><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></description>';
        // 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') {
        $context['recent_posts_data'] = $xml;
        // 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(), '
				', template_webslice_header_below(), '
			]]></description>
		</item>
	</channel>
</rss>';
    } elseif ($xml_format == 'atom') {
        echo '
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>', $feed_title, '</title>
	<link rel="alternate" type="text/html" href="', $scripturl, '" />

	<modified>', gmstrftime('%Y-%m-%dT%H:%M:%SZ'), '</modified>
	<tagline><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></tagline>
	<generator uri="http://www.simplemachines.org" version="', strtr($forum_version, array('SMF' => '')), '">SMF</generator>
	<author>
		<name>', strip_tags($context['forum_name']), '</name>
	</author>';
        dumpTags($xml, 2, 'entry', $xml_format);
        echo '
</feed>';
    } elseif ($xml_format == 'rdf') {
        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>';
    } else {
        echo '
<smf:xml-feed xmlns:smf="http://www.simplemachines.org/" xmlns="http://www.simplemachines.org/xml/', $_GET['sa'], '" xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">';
        // Dump out that associative array.  Indent properly.... and use the right names for the base elements.
        dumpTags($xml, 1, $subActions[$_GET['sa']][1], $xml_format);
        echo '
</smf:xml-feed>';
    }
    obExit(false);
}
Exemple #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);
    }