Esempio n. 1
0
function atom()
{
    global $thisarticle;
    extract($GLOBALS['prefs']);
    define("t_texthtml", ' type="text/html"');
    define("t_text", ' type="text"');
    define("t_html", ' type="html"');
    define("t_xhtml", ' type="xhtml"');
    define('t_appxhtml', ' type="xhtml"');
    define("r_relalt", ' rel="alternate"');
    define("r_relself", ' rel="self"');
    $area = doSlash(gps('area'));
    extract(doSlash(gpsa(array('category', 'section', 'limit'))));
    $last = fetch('unix_timestamp(val)', 'txp_prefs', 'name', 'lastmod');
    $sitename .= $section ? ' - ' . $section : '';
    $sitename .= $category ? ' - ' . $category : '';
    $pub = safe_row("RealName, email", "txp_users", "privs=1");
    $out[] = tag(escape_output($sitename), 'title', t_text);
    $out[] = tag(escape_output($site_slogan), 'subtitle', t_text);
    $out[] = '<link' . r_relself . ' href="' . pagelinkurl(array('atom' => 1, 'area' => $area, 'section' => $section, 'category' => $category, 'limit' => $limit)) . '" />';
    $out[] = '<link' . r_relalt . t_texthtml . ' href="' . hu . '" />';
    $articles = array();
    //Atom feeds with mail or domain name
    $dn = explode('/', $siteurl);
    $mail_or_domain = $use_mail_on_feeds_id ? eE($blog_mail_uid) : $dn[0];
    $out[] = tag('tag:' . $mail_or_domain . ',' . $blog_time_uid . ':' . $blog_uid . ($section ? '/' . $section : '') . ($category ? '/' . $category : ''), 'id');
    $out[] = tag('Textpattern', 'generator', ' uri="http://textpattern.com/" version="' . $version . '"');
    $out[] = tag(safe_strftime("w3cdtf", $last), 'updated');
    $auth[] = tag($pub['RealName'], 'name');
    $auth[] = $include_email_atom ? tag(eE($pub['email']), 'email') : '';
    $auth[] = tag(hu, 'uri');
    $out[] = tag(n . t . t . join(n . t . t, $auth) . n, 'author');
    if (!$area or $area == 'article') {
        $sfilter = $section ? "and Section = '" . $section . "'" : '';
        $cfilter = $category ? "and (Category1='" . $category . "' or Category2='" . $category . "')" : '';
        $limit = $limit ? $limit : $rss_how_many;
        $limit = intval(min($limit, max(100, $rss_how_many)));
        $frs = safe_column("name", "txp_section", "in_rss != '1'");
        $query = array();
        foreach ($frs as $f) {
            $query[] = "and Section != '" . doSlash($f) . "'";
        }
        $query[] = $sfilter;
        $query[] = $cfilter;
        $rs = safe_rows_start("*, \n\t\t\t\tID as thisid, \n\t\t\t\tunix_timestamp(Posted) as uPosted,\n\t\t\t\tunix_timestamp(LastMod) as uLastMod", "textpattern", "Status=4 and Posted <= now() " . join(' ', $query) . "order by Posted desc limit {$limit}");
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                populateArticleData($a);
                $cb = callback_event('atom_entry');
                $e = array();
                $a['posted'] = $uPosted;
                if ($show_comment_count_in_feed) {
                    $count = $comments_count > 0 ? ' [' . $comments_count . ']' : '';
                } else {
                    $count = '';
                }
                $thisauthor = get_author_name($AuthorID);
                $e['thisauthor'] = tag(n . t . t . t . tag(htmlspecialchars($thisauthor), 'name') . n . t . t, 'author');
                $e['issued'] = tag(safe_strftime('w3cdtf', $uPosted), 'published');
                $e['modified'] = tag(safe_strftime('w3cdtf', $uLastMod), 'updated');
                $escaped_title = escape_output($Title);
                $e['title'] = tag($escaped_title . $count, 'title', t_html);
                $permlink = permlinkurl($a);
                $e['link'] = '<link' . r_relalt . t_texthtml . ' href="' . $permlink . '" />';
                $e['id'] = tag('tag:' . $mail_or_domain . ',' . $feed_time . ':' . $blog_uid . '/' . $uid, 'id');
                $e['category1'] = trim($Category1) ? '<category term="' . htmlspecialchars($Category1) . '" />' : '';
                $e['category2'] = trim($Category2) ? '<category term="' . htmlspecialchars($Category2) . '" />' : '';
                $summary = trim(replace_relative_urls(parse($thisarticle['excerpt']), $permlink));
                $content = trim(replace_relative_urls(parse($thisarticle['body']), $permlink));
                if ($syndicate_body_or_excerpt) {
                    # short feed: use body as summary if there's no excerpt
                    if (!trim($summary)) {
                        $summary = $content;
                    }
                    $content = '';
                }
                if (trim($content)) {
                    $e['content'] = tag(n . escape_cdata($content) . n, 'content', t_html);
                }
                if (trim($summary)) {
                    $e['summary'] = tag(n . escape_cdata($summary) . n, 'summary', t_html);
                }
                $articles[$ID] = tag(n . t . t . join(n . t . t, $e) . n . $cb, 'entry');
                $etags[$ID] = strtoupper(dechex(crc32($articles[$ID])));
                $dates[$ID] = $uLastMod;
            }
        }
    } elseif ($area == 'link') {
        $cfilter = $category ? "category='" . $category . "'" : '1';
        $limit = $limit ? $limit : $rss_how_many;
        $limit = intval(min($limit, max(100, $rss_how_many)));
        $rs = safe_rows_start("*", "txp_link", "{$cfilter} order by date desc, id desc limit {$limit}");
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                $e['title'] = tag(htmlspecialchars($linkname), 'title', t_html);
                $e['content'] = tag(n . htmlspecialchars($description) . n, 'content', t_html);
                $url = preg_replace("/^\\/(.*)/", "https?://{$siteurl}/\$1", $url);
                $url = preg_replace("/&((?U).*)=/", "&amp;\\1=", $url);
                $e['link'] = '<link' . r_relalt . t_texthtml . ' href="' . $url . '" />';
                $e['issued'] = tag(safe_strftime('w3cdtf', strtotime($date)), 'published');
                $e['modified'] = tag(gmdate('Y-m-d\\TH:i:s\\Z', strtotime($date)), 'updated');
                $e['id'] = tag('tag:' . $mail_or_domain . ',' . $feed_time . ':' . $id, 'id');
                $articles[$id] = tag(n . t . t . join(n . t . t, $e) . n, 'entry');
                $etags[$id] = strtoupper(dechex(crc32($articles[$id])));
                $dates[$id] = $date;
            }
        }
    }
    if (!empty($articles)) {
        //turn on compression if we aren't using it already
        if (extension_loaded('zlib') && ini_get("zlib.output_compression") == 0 && ini_get('output_handler') != 'ob_gzhandler' && !headers_sent()) {
            @ob_start("ob_gzhandler");
        }
        handle_lastmod();
        $hims = serverset('HTTP_IF_MODIFIED_SINCE');
        $imsd = $hims ? strtotime($hims) : 0;
        if ($imsd >= $last) {
            txp_status_header("304 Not Modified");
            exit;
        }
        header("Last-Modified: " . gmdate('D, d M Y H:i:s \\G\\M\\T', $last));
        if (is_callable('apache_request_headers')) {
            $headers = apache_request_headers();
            if (isset($headers["A-IM"])) {
                $canaim = strpos($headers["A-IM"], "feed");
            } else {
                $canaim = false;
            }
        } else {
            $canaim = false;
        }
        $hinm = stripslashes(serverset('HTTP_IF_NONE_MATCH'));
        $cutarticles = false;
        if ($canaim !== false) {
            foreach ($articles as $id => $thing) {
                if (strpos($hinm, $etags[$id])) {
                    unset($articles[$id]);
                    $cutarticles = true;
                    $cut_etag = true;
                }
                if ($dates[$id] < $imsd) {
                    unset($articles[$id]);
                    $cutarticles = true;
                    $cut_time = true;
                }
            }
        }
        if (isset($cut_etag) && isset($cut_time)) {
            header("Vary: If-None-Match, If-Modified-Since");
        } else {
            if (isset($cut_etag)) {
                header("Vary: If-None-Match");
            } else {
                if (isset($cut_time)) {
                    header("Vary: If-Modified-Since");
                }
            }
        }
        $etag = @join("-", $etags);
        if (strstr($hinm, $etag)) {
            header("HTTP/1.1 304 Not Modified");
            exit;
        }
        if ($etag) {
            header('ETag: "' . $etag . '"');
        }
        if ($cutarticles) {
            //header("HTTP/1.1 226 IM Used");
            //This should be used as opposed to 200, but Apache doesn't like it.
            //http://intertwingly.net/blog/2004/09/11/Vary-ETag/ says that the status code should be 200.
            header("Cache-Control: no-store, im");
            header("IM: feed");
        }
        $out = array_merge($out, $articles);
        header('Content-type: application/atom+xml; charset=utf-8');
        return chr(60) . '?xml version="1.0" encoding="UTF-8"?' . chr(62) . n . '<feed xml:lang="' . $language . '" xmlns="http://www.w3.org/2005/Atom">' . join(n, $out) . '</feed>';
    }
}
Esempio n. 2
0
function rss()
{
    global $prefs, $thisarticle;
    set_error_handler('feedErrorHandler');
    ob_clean();
    extract($prefs);
    extract(doSlash(gpsa(array('limit', 'area'))));
    // build filter criteria from a comma-separated list of sections and categories
    $feed_filter_limit = get_pref('feed_filter_limit', 10);
    $section = gps('section');
    $category = gps('category');
    if (!is_scalar($section) || !is_scalar($category)) {
        txp_die('Not Found', 404);
    }
    $section = $section ? array_slice(array_unique(do_list($section)), 0, $feed_filter_limit) : array();
    $category = $category ? array_slice(array_unique(do_list($category)), 0, $feed_filter_limit) : array();
    $st = array();
    foreach ($section as $s) {
        $st[] = fetch_section_title($s);
    }
    $ct = array();
    foreach ($category as $c) {
        $ct[] = fetch_category_title($c);
    }
    $sitename .= $section ? ' - ' . join(' - ', $st) : '';
    $sitename .= $category ? ' - ' . join(' - ', $ct) : '';
    $dn = explode('/', $siteurl);
    $mail_or_domain = $use_mail_on_feeds_id ? eE($blog_mail_uid) : $dn[0];
    // feed header
    $out[] = tag('http://textpattern.com/?v=' . $version, 'generator');
    $out[] = tag(doSpecial($sitename), 'title');
    $out[] = tag(hu, 'link');
    $out[] = '<atom:link href="' . pagelinkurl(array('rss' => 1, 'area' => $area, 'section' => $section, 'category' => $category, 'limit' => $limit)) . '" rel="self" type="application/rss+xml" />';
    $out[] = tag(doSpecial($site_slogan), 'description');
    $last = fetch('unix_timestamp(val)', 'txp_prefs', 'name', 'lastmod');
    $out[] = tag(safe_strftime('rfc822', $last), 'pubDate');
    $out[] = callback_event('rss_head');
    // feed items
    $articles = array();
    $section = doSlash($section);
    $category = doSlash($category);
    if (!$area or $area == 'article') {
        $sfilter = !empty($section) ? "and Section in ('" . join("','", $section) . "')" : '';
        $cfilter = !empty($category) ? "and (Category1 in ('" . join("','", $category) . "') or Category2 in ('" . join("','", $category) . "'))" : '';
        $limit = $limit ? $limit : $rss_how_many;
        $limit = intval(min($limit, max(100, $rss_how_many)));
        $frs = safe_column("name", "txp_section", "in_rss != '1'");
        if ($frs) {
            foreach ($frs as $f) {
                $query[] = "and Section != '" . doSlash($f) . "'";
            }
        }
        $query[] = $sfilter;
        $query[] = $cfilter;
        $expired = $publish_expired_articles ? '' : ' and (now() <= Expires or Expires = ' . NULLDATETIME . ') ';
        $rs = safe_rows_start("*, unix_timestamp(Posted) as uPosted, unix_timestamp(LastMod) as uLastMod, unix_timestamp(Expires) as uExpires, ID as thisid", "textpattern", "Status = 4 " . join(' ', $query) . "and Posted < now()" . $expired . "order by Posted desc limit {$limit}");
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                populateArticleData($a);
                $cb = callback_event('rss_entry');
                $a['posted'] = $uPosted;
                $permlink = permlinkurl($a);
                $summary = trim(replace_relative_urls(parse($thisarticle['excerpt']), $permlink));
                $content = trim(replace_relative_urls(parse($thisarticle['body']), $permlink));
                if ($syndicate_body_or_excerpt) {
                    # short feed: use body as summary if there's no excerpt
                    if (!trim($summary)) {
                        $summary = $content;
                    }
                    $content = '';
                }
                if ($show_comment_count_in_feed) {
                    $count = $comments_count > 0 ? ' [' . $comments_count . ']' : '';
                } else {
                    $count = '';
                }
                $Title = escape_title(strip_tags($Title)) . $count;
                $thisauthor = get_author_name($AuthorID);
                $item = tag($Title, 'title') . n . (trim($summary) ? tag(n . escape_cdata($summary) . n, 'description') . n : '') . (trim($content) ? tag(n . escape_cdata($content) . n, 'content:encoded') . n : '') . tag($permlink, 'link') . n . tag(safe_strftime('rfc822', $a['posted']), 'pubDate') . n . tag(htmlspecialchars($thisauthor), 'dc:creator') . n . tag('tag:' . $mail_or_domain . ',' . $feed_time . ':' . $blog_uid . '/' . $uid, 'guid', ' isPermaLink="false"') . n . $cb;
                $articles[$ID] = tag($item, 'item');
                $etags[$ID] = strtoupper(dechex(crc32($articles[$ID])));
                $dates[$ID] = $uPosted;
            }
        }
    } elseif ($area == 'link') {
        $cfilter = $category ? "category in ('" . join("','", $category) . "')" : '1';
        $limit = $limit ? $limit : $rss_how_many;
        $limit = intval(min($limit, max(100, $rss_how_many)));
        $rs = safe_rows_start("*, unix_timestamp(date) as uDate", "txp_link", "{$cfilter} order by date desc limit {$limit}");
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                $item = tag(doSpecial($linkname), 'title') . n . tag(doSpecial($description), 'description') . n . tag(doSpecial($url), 'link') . n . tag(safe_strftime('rfc822', $uDate), 'pubDate');
                $articles[$id] = tag($item, 'item');
                $etags[$id] = strtoupper(dechex(crc32($articles[$id])));
                $dates[$id] = $date;
            }
        }
    }
    if (!$articles) {
        if ($section) {
            if (safe_field('name', 'txp_section', "name in ('" . join("','", $section) . "')") == false) {
                txp_die(gTxt('404_not_found'), '404');
            }
        } elseif ($category) {
            switch ($area) {
                case 'link':
                    if (safe_field('id', 'txp_category', "name = '{$category}' and type = 'link'") == false) {
                        txp_die(gTxt('404_not_found'), '404');
                    }
                    break;
                case 'article':
                default:
                    if (safe_field('id', 'txp_category', "name in ('" . join("','", $category) . "') and type = 'article'") == false) {
                        txp_die(gTxt('404_not_found'), '404');
                    }
                    break;
            }
        }
    } else {
        //turn on compression if we aren't using it already
        if (extension_loaded('zlib') && ini_get("zlib.output_compression") == 0 && ini_get('output_handler') != 'ob_gzhandler' && !headers_sent()) {
            // make sure notices/warnings/errors don't fudge up the feed
            // when compression is used
            $buf = '';
            while ($b = @ob_get_clean()) {
                $buf .= $b;
            }
            @ob_start('ob_gzhandler');
            echo $buf;
        }
        handle_lastmod();
        $hims = serverset('HTTP_IF_MODIFIED_SINCE');
        $imsd = $hims ? strtotime($hims) : 0;
        if (is_callable('apache_request_headers')) {
            $headers = apache_request_headers();
            if (isset($headers["A-IM"])) {
                $canaim = strpos($headers["A-IM"], "feed");
            } else {
                $canaim = false;
            }
        } else {
            $canaim = false;
        }
        $hinm = stripslashes(serverset('HTTP_IF_NONE_MATCH'));
        $cutarticles = false;
        if ($canaim !== false) {
            foreach ($articles as $id => $thing) {
                if (strpos($hinm, $etags[$id]) !== false) {
                    unset($articles[$id]);
                    $cutarticles = true;
                    $cut_etag = true;
                }
                if ($dates[$id] < $imsd) {
                    unset($articles[$id]);
                    $cutarticles = true;
                    $cut_time = true;
                }
            }
        }
        if (isset($cut_etag) && isset($cut_time)) {
            header("Vary: If-None-Match, If-Modified-Since");
        } else {
            if (isset($cut_etag)) {
                header("Vary: If-None-Match");
            } else {
                if (isset($cut_time)) {
                    header("Vary: If-Modified-Since");
                }
            }
        }
        $etag = @join("-", $etags);
        if (strstr($hinm, $etag)) {
            txp_status_header('304 Not Modified');
            exit(0);
        }
        if ($cutarticles) {
            //header("HTTP/1.1 226 IM Used");
            //This should be used as opposed to 200, but Apache doesn't like it.
            //http://intertwingly.net/blog/2004/09/11/Vary-ETag/ says that the status code should be 200.
            header("Cache-Control: no-store, im");
            header("IM: feed");
        }
    }
    $out = array_merge($out, $articles);
    header("Content-Type: application/rss+xml; charset=utf-8");
    if (isset($etag)) {
        header('ETag: "' . $etag . '"');
    }
    return '<?xml version="1.0" encoding="utf-8"?>' . n . '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">' . n . tag(join(n, $out), 'channel') . n . '</rss>';
}
Esempio n. 3
0
function render_feed($rs, $area, $type, $feedtitle, $atom_self_ref, $atom_id_ext)
{
    global $prefs, $thisarticle;
    extract($prefs);
    set_error_handler('tagErrorHandler');
    $atom = $type == 'atom';
    if ($atom) {
        define("t_texthtml", ' type="text/html"');
        define("t_text", ' type="text"');
        define("t_html", ' type="html"');
        define("t_xhtml", ' type="xhtml"');
        define('t_appxhtml', ' type="xhtml"');
        define("r_relalt", ' rel="alternate"');
        define("r_relself", ' rel="self"');
    } else {
        define("t_texthtml", '');
        define("t_text", '');
        define("t_html", '');
        define("t_xhtml", '');
        define('t_appxhtml', '');
        define("r_relalt", '');
        define("r_relself", '');
    }
    $dn = explode('/', $siteurl);
    $mail_or_domain = $use_mail_on_feeds_id ? eE($blog_mail_uid) : $dn[0];
    $last = fetch('unix_timestamp(val)', 'txp_prefs', 'name', 'lastmod');
    if ($atom) {
        $out[] = tag('Textpattern', 'generator', ' uri="http://textpattern.com/" version="' . $version . '"');
        $out[] = tag(htmlspecialchars($feedtitle), 'title', t_text);
        $out[] = tag(htmlspecialchars($site_slogan), 'subtitle', t_text);
        $out[] = tag(safe_strftime("w3cdtf", $last), 'updated');
        $out[] = '<link' . r_relself . ' href="' . $atom_self_ref . '" />';
        $out[] = '<link' . r_relalt . t_texthtml . ' href="' . hu . '" />';
        //Atom feeds with mail or domain name
        $out[] = tag('tag:' . $mail_or_domain . ',' . $blog_time_uid . ':' . $blog_uid . $atom_id_ext, 'id');
        $pub = safe_row("RealName, email", "txp_users", "privs=1");
        $auth[] = tag($pub['RealName'], 'name');
        $auth[] = $include_email_atom ? tag(eE($pub['email']), 'email') : '';
        $auth[] = tag(hu, 'uri');
        $out[] = tag(n . t . t . join(n . t . t, $auth) . n, 'author');
    } else {
        $out[] = tag('http://textpattern.com/?v=' . $version, 'generator');
        $out[] = tag(doSpecial($feedtitle), 'title');
        $out[] = tag(doSpecial($site_slogan), 'description');
        $out[] = tag(safe_strftime('rfc822', $last), 'pubDate');
        $out[] = tag(hu, 'link');
        $out[] = '<atom:link href="' . $atom_self_ref . '" rel="self" type="application/rss+xml" />';
    }
    $out[] = callback_event($atom ? 'atom_head' : 'rss_head');
    $articles = array();
    if (!$area or $area == 'article') {
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                populateArticleData($a);
                $cb = callback_event($atom ? 'atom_entry' : 'rss_entry');
                $e = array();
                $thisauthor = doSpecial(get_author_name($AuthorID));
                $thisauthor = tag($thisauthor, $atom ? 'name' : 'dc:creator');
                if ($atom) {
                    $thisauthor = tag(n . t . t . t . $thisauthor . n . t . t, 'author');
                }
                $e['thisauthor'] = $thisauthor;
                if ($atom) {
                    $e['issued'] = tag(safe_strftime('w3cdtf', $uPosted), 'published');
                } else {
                    $e['issued'] = tag(safe_strftime('rfc822', $uPosted), 'pubDate');
                }
                if ($atom) {
                    $e['modified'] = tag(safe_strftime('w3cdtf', $uLastMod), 'updated');
                    $e['category1'] = trim($Category1) ? '<category term="' . doSpecial($Category1) . '" />' : '';
                    $e['category2'] = trim($Category2) ? '<category term="' . doSpecial($Category2) . '" />' : '';
                }
                $count = '';
                if ($show_comment_count_in_feed && $comments_count > 0) {
                    $count = ' [' . $comments_count . ']';
                }
                $escaped_title = $atom ? htmlspecialchars($Title) : htmlspecialchars(strip_tags($Title));
                $e['title'] = tag($escaped_title . $count, 'title', t_html);
                $a['posted'] = $uPosted;
                $permlink = permlinkurl($a);
                if ($atom) {
                    $e['link'] = '<link' . r_relalt . t_texthtml . ' href="' . $permlink . '" />';
                } else {
                    $e['link'] = tag($permlink, 'link');
                }
                $e['id'] = tag('tag:' . $mail_or_domain . ',' . $feed_time . ':' . $blog_uid . '/' . $uid, $atom ? 'id' : 'guid', $atom ? '' : ' isPermaLink="false"');
                $summary = trim(replace_relative_urls(parse($thisarticle['excerpt']), $permlink));
                $content = trim(replace_relative_urls(parse($thisarticle['body']), $permlink));
                if ($syndicate_body_or_excerpt) {
                    # short feed: use body as summary if there's no excerpt
                    if (!trim($summary)) {
                        $summary = $content;
                    }
                    $content = '';
                }
                if (trim($summary)) {
                    $e['summary'] = tag(n . escape_cdata($summary) . n, $atom ? 'summary' : 'description', t_html);
                }
                if (trim($content)) {
                    $e['content'] = tag(n . escape_cdata($content) . n, $atom ? 'content' : 'content:encoded', t_html);
                }
                $articles[$ID] = tag(n . t . t . join(n . t . t, $e) . n . $cb, $atom ? 'entry' : 'item');
                $etags[$ID] = strtoupper(dechex(crc32($articles[$ID])));
                $dates[$ID] = $atom ? $uLastMod : $uPosted;
            }
        }
    } elseif ($area == 'link') {
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                $e['title'] = tag(doSpecial($linkname), 'title', t_html);
                if ($atom) {
                    $e['content'] = tag(n . doSpecial($description) . n, 'content', t_html);
                    $url = preg_replace("/^\\/(.*)/", "https?://{$siteurl}/\$1", $url);
                    $url = preg_replace("/&((?U).*)=/", "&amp;\\1=", $url);
                    $e['link'] = '<link' . r_relalt . t_texthtml . ' href="' . $url . '" />';
                    $e['issued'] = tag(safe_strftime('w3cdtf', strtotime($date)), 'published');
                    $e['modified'] = tag(gmdate('Y-m-d\\TH:i:s\\Z', strtotime($date)), 'updated');
                    $e['id'] = tag('tag:' . $mail_or_domain . ',' . safe_strftime('%Y-%m-%d', strtotime($date)) . ':' . $blog_uid . '/' . $id, 'id');
                } else {
                    $e['content'] = tag(doSpecial($description), 'description');
                    $e['link'] = tag(doSpecial($url), 'link');
                    $e['issued'] = tag(safe_strftime('rfc822', $uDate), 'pubDate');
                }
                $articles[$id] = tag(n . t . t . join(n . t . t, $e) . n, $atom ? 'entry' : 'item');
                $etags[$id] = strtoupper(dechex(crc32($articles[$id])));
                $dates[$id] = $date;
            }
        }
    }
    if (!$articles) {
        if ($section) {
            if (safe_field('name', 'txp_section', "name = '{$section}'") == false) {
                txp_die(gTxt('404_not_found'), '404');
            }
        } elseif ($category) {
            switch ($area) {
                case 'link':
                    if (safe_field('id', 'txp_category', "name = '{$category}' and type = 'link'") == false) {
                        txp_die(gTxt('404_not_found'), '404');
                    }
                    break;
                case 'article':
                default:
                    if (safe_field('id', 'txp_category', "name = '{$category}' and type = 'article'") == false) {
                        txp_die(gTxt('404_not_found'), '404');
                    }
                    break;
            }
        }
    } else {
        //turn on compression if we aren't using it already
        if (extension_loaded('zlib') && ini_get("zlib.output_compression") == 0 && ini_get('output_handler') != 'ob_gzhandler' && !headers_sent()) {
            // make sure notices/warnings/errors don't
            // fudge up the feed when compression is used
            $buf = '';
            while ($b = @ob_get_clean()) {
                $buf .= $b;
            }
            @ob_start('ob_gzhandler');
            echo $buf;
        }
        handle_lastmod();
        $hims = serverset('HTTP_IF_MODIFIED_SINCE');
        $imsd = $hims ? strtotime($hims) : 0;
        if (is_callable('apache_request_headers')) {
            $headers = apache_request_headers();
            if (isset($headers["A-IM"])) {
                $canaim = strpos($headers["A-IM"], "feed");
            } else {
                $canaim = false;
            }
        } else {
            $canaim = false;
        }
        $hinm = stripslashes(serverset('HTTP_IF_NONE_MATCH'));
        $cutarticles = false;
        if ($canaim !== false) {
            foreach ($articles as $id => $thing) {
                if (strpos($hinm, $etags[$id]) !== false) {
                    unset($articles[$id]);
                    $cutarticles = true;
                    $cut_etag = true;
                }
                if ($dates[$id] < $imsd) {
                    unset($articles[$id]);
                    $cutarticles = true;
                    $cut_time = true;
                }
            }
        }
        if (isset($cut_etag) && isset($cut_time)) {
            header("Vary: If-None-Match, If-Modified-Since");
        } else {
            if (isset($cut_etag)) {
                header("Vary: If-None-Match");
            } else {
                if (isset($cut_time)) {
                    header("Vary: If-Modified-Since");
                }
            }
        }
        $etag = @join("-", $etags);
        if (strstr($hinm, $etag)) {
            txp_status_header('304 Not Modified');
            exit(0);
        }
        if ($etag) {
            header('ETag: "' . $etag . '"');
        }
        if ($cutarticles) {
            //header("HTTP/1.1 226 IM Used");
            //This should be used as opposed to 200, but Apache doesn't like it.
            //http://intertwingly.net/blog/2004/09/11/Vary-ETag/ says that the status code should be 200.
            header("Cache-Control: no-store, im");
            header("IM: feed");
        }
    }
    $out = array_merge($out, $articles);
    header('Content-type: application/' . ($atom ? 'atom' : 'rss') . '+xml; charset=utf-8');
    if ($atom) {
        return chr(60) . '?xml version="1.0" encoding="UTF-8"?' . chr(62) . n . '<feed xml:lang="' . $language . '" xmlns="http://www.w3.org/2005/Atom">' . n . join(n, $out) . '</feed>';
    } else {
        return '<?xml version="1.0" encoding="utf-8"?>' . n . '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">' . n . tag(join(n, $out), 'channel') . n . '</rss>';
    }
}
Esempio n. 4
0
/**
 * Generates and outputs an Atom feed.
 *
 * This function can only be called once on a page. It outputs an Atom feed
 * based on the requested URL parameters. Accepts HTTP GET parameters 'limit',
 * 'area', 'section' and 'category'.
 */
function atom()
{
    global $thisarticle, $prefs;
    set_error_handler('feedErrorHandler');
    ob_clean();
    extract($prefs);
    $last = fetch("UNIX_TIMESTAMP(val)", 'txp_prefs', 'name', 'lastmod');
    extract(doSlash(gpsa(array('limit', 'area'))));
    // Build filter criteria from a comma-separated list of sections
    // and categories.
    $feed_filter_limit = get_pref('feed_filter_limit', 10);
    $section = gps('section');
    $category = gps('category');
    if (!is_scalar($section) || !is_scalar($category)) {
        txp_die('Not Found', 404);
    }
    $section = $section ? array_slice(do_list_unique($section), 0, $feed_filter_limit) : array();
    $category = $category ? array_slice(do_list_unique($category), 0, $feed_filter_limit) : array();
    $st = array();
    foreach ($section as $s) {
        $st[] = fetch_section_title($s);
    }
    $ct = array();
    foreach ($category as $c) {
        $ct[] = fetch_category_title($c);
    }
    $sitename .= $section ? ' - ' . join(' - ', $st) : '';
    $sitename .= $category ? ' - ' . join(' - ', $ct) : '';
    $pub = safe_row("RealName, email", 'txp_users', "privs = 1");
    // Feed header.
    $out[] = tag(htmlspecialchars($sitename), 'title', t_text);
    $out[] = tag(htmlspecialchars($site_slogan), 'subtitle', t_text);
    $out[] = '<link' . r_relself . ' href="' . pagelinkurl(array('atom' => 1, 'area' => $area, 'section' => $section, 'category' => $category, 'limit' => $limit)) . '" />';
    $out[] = '<link' . r_relalt . t_texthtml . ' href="' . hu . '" />';
    // Atom feeds with mail or domain name.
    $dn = explode('/', $siteurl);
    $mail_or_domain = $use_mail_on_feeds_id ? eE($blog_mail_uid) : $dn[0];
    $out[] = tag('tag:' . $mail_or_domain . ',' . $blog_time_uid . ':' . $blog_uid . ($section ? '/' . join(',', $section) : '') . ($category ? '/' . join(',', $category) : ''), 'id');
    $out[] = tag('Textpattern', 'generator', ' uri="http://textpattern.com/" version="' . $version . '"');
    $out[] = tag(safe_strftime("w3cdtf", $last), 'updated');
    $auth[] = tag($pub['RealName'], 'name');
    $auth[] = $include_email_atom ? tag(eE($pub['email']), 'email') : '';
    $auth[] = tag(hu, 'uri');
    $out[] = tag(n . t . t . join(n . t . t, $auth) . n, 'author');
    $out[] = callback_event('atom_head');
    // Feed items.
    $articles = array();
    $section = doSlash($section);
    $category = doSlash($category);
    if (!$area or $area == 'article') {
        $sfilter = !empty($section) ? "AND Section IN ('" . join("','", $section) . "')" : '';
        $cfilter = !empty($category) ? "AND (Category1 IN ('" . join("','", $category) . "') OR Category2 IN ('" . join("','", $category) . "'))" : '';
        $limit = $limit ? $limit : $rss_how_many;
        $limit = intval(min($limit, max(100, $rss_how_many)));
        $frs = safe_column("name", 'txp_section', "in_rss != '1'");
        $query = array();
        foreach ($frs as $f) {
            $query[] = "AND Section != '" . doSlash($f) . "'";
        }
        $query[] = $sfilter;
        $query[] = $cfilter;
        $expired = $publish_expired_articles ? " " : " AND (" . now('expires') . " <= Expires OR Expires = " . NULLDATETIME . ") ";
        $rs = safe_rows_start("*,\n            ID AS thisid,\n            UNIX_TIMESTAMP(Posted) AS uPosted,\n            UNIX_TIMESTAMP(Expires) AS uExpires,\n            UNIX_TIMESTAMP(LastMod) AS uLastMod", 'textpattern', "Status = 4 AND Posted <= " . now('posted') . $expired . join(' ', $query) . "ORDER BY Posted DESC LIMIT {$limit}");
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                populateArticleData($a);
                $cb = callback_event('atom_entry');
                $e = array();
                $a['posted'] = $uPosted;
                $a['expires'] = $uExpires;
                if ($show_comment_count_in_feed) {
                    $count = $comments_count > 0 ? ' [' . $comments_count . ']' : '';
                } else {
                    $count = '';
                }
                $thisauthor = get_author_name($AuthorID);
                $e['thisauthor'] = tag(n . t . t . t . tag(htmlspecialchars($thisauthor), 'name') . n . t . t, 'author');
                $e['issued'] = tag(safe_strftime('w3cdtf', $uPosted), 'published');
                $e['modified'] = tag(safe_strftime('w3cdtf', $uLastMod), 'updated');
                $escaped_title = htmlspecialchars($Title);
                $e['title'] = tag($escaped_title . $count, 'title', t_html);
                $permlink = permlinkurl($a);
                $e['link'] = '<link' . r_relalt . t_texthtml . ' href="' . $permlink . '" />';
                $e['id'] = tag('tag:' . $mail_or_domain . ',' . $feed_time . ':' . $blog_uid . '/' . $uid, 'id');
                $e['category1'] = trim($Category1) ? '<category term="' . htmlspecialchars($Category1) . '" />' : '';
                $e['category2'] = trim($Category2) ? '<category term="' . htmlspecialchars($Category2) . '" />' : '';
                $summary = trim(replace_relative_urls(parse($thisarticle['excerpt']), $permlink));
                $content = trim(replace_relative_urls(parse($thisarticle['body']), $permlink));
                if ($syndicate_body_or_excerpt) {
                    // Short feed: use body as summary if there's no excerpt.
                    if (!trim($summary)) {
                        $summary = $content;
                    }
                    $content = '';
                }
                if (trim($content)) {
                    $e['content'] = tag(n . escape_cdata($content) . n, 'content', t_html);
                }
                if (trim($summary)) {
                    $e['summary'] = tag(n . escape_cdata($summary) . n, 'summary', t_html);
                }
                $articles[$ID] = tag(n . t . t . join(n . t . t, $e) . n . $cb, 'entry');
                $etags[$ID] = strtoupper(dechex(crc32($articles[$ID])));
                $dates[$ID] = $uLastMod;
            }
        }
    } elseif ($area == 'link') {
        $cfilter = $category ? "category in ('" . join("','", $category) . "')" : '1';
        $limit = $limit ? $limit : $rss_how_many;
        $limit = intval(min($limit, max(100, $rss_how_many)));
        $rs = safe_rows_start("*", 'txp_link', "{$cfilter} ORDER BY date DESC, id DESC LIMIT {$limit}");
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                $e['title'] = tag(htmlspecialchars($linkname), 'title', t_html);
                $e['content'] = tag(n . htmlspecialchars($description) . n, 'content', t_html);
                $url = preg_replace("/^\\/(.*)/", "https?://{$siteurl}/\$1", $url);
                $url = preg_replace("/&((?U).*)=/", "&amp;\\1=", $url);
                $e['link'] = '<link' . r_relalt . t_texthtml . ' href="' . $url . '" />';
                $e['issued'] = tag(safe_strftime('w3cdtf', strtotime($date)), 'published');
                $e['modified'] = tag(gmdate('Y-m-d\\TH:i:s\\Z', strtotime($date)), 'updated');
                $e['id'] = tag('tag:' . $mail_or_domain . ',' . safe_strftime('%Y-%m-%d', strtotime($date)) . ':' . $blog_uid . '/' . $id, 'id');
                $articles[$id] = tag(n . t . t . join(n . t . t, $e) . n, 'entry');
                $etags[$id] = strtoupper(dechex(crc32($articles[$id])));
                $dates[$id] = $date;
            }
        }
    }
    if (!$articles) {
        if ($section) {
            if (safe_field("name", 'txp_section', "name IN ('" . join("','", $section) . "')") == false) {
                txp_die(gTxt('404_not_found'), '404');
            }
        } elseif ($category) {
            switch ($area) {
                case 'link':
                    if (safe_field("id", 'txp_category', "name = '{$category}' AND type = 'link'") == false) {
                        txp_die(gTxt('404_not_found'), '404');
                    }
                    break;
                case 'article':
                default:
                    if (safe_field("id", 'txp_category', "name IN ('" . join("','", $category) . "') AND type = 'article'") == false) {
                        txp_die(gTxt('404_not_found'), '404');
                    }
                    break;
            }
        }
    } else {
        // Turn on compression if we aren't using it already.
        if (extension_loaded('zlib') && ini_get("zlib.output_compression") == 0 && ini_get('output_handler') != 'ob_gzhandler' && !headers_sent()) {
            // Make sure notices/warnings/errors don't fudge up the feed when
            // compression is used.
            $buf = '';
            while ($b = @ob_get_clean()) {
                $buf .= $b;
            }
            @ob_start('ob_gzhandler');
            echo $buf;
        }
        handle_lastmod();
        $hims = serverset('HTTP_IF_MODIFIED_SINCE');
        $imsd = $hims ? strtotime($hims) : 0;
        if (is_callable('apache_request_headers')) {
            $headers = apache_request_headers();
            if (isset($headers["A-IM"])) {
                $canaim = strpos($headers["A-IM"], "feed");
            } else {
                $canaim = false;
            }
        } else {
            $canaim = false;
        }
        $hinm = stripslashes(serverset('HTTP_IF_NONE_MATCH'));
        $cutarticles = false;
        if ($canaim !== false) {
            foreach ($articles as $id => $thing) {
                if (strpos($hinm, $etags[$id])) {
                    unset($articles[$id]);
                    $cutarticles = true;
                    $cut_etag = true;
                }
                if ($dates[$id] < $imsd) {
                    unset($articles[$id]);
                    $cutarticles = true;
                    $cut_time = true;
                }
            }
        }
        if (isset($cut_etag) && isset($cut_time)) {
            header("Vary: If-None-Match, If-Modified-Since");
        } elseif (isset($cut_etag)) {
            header("Vary: If-None-Match");
        } elseif (isset($cut_time)) {
            header("Vary: If-Modified-Since");
        }
        $etag = @join("-", $etags);
        if (strstr($hinm, $etag)) {
            txp_status_header('304 Not Modified');
            exit(0);
        }
        if ($etag) {
            header('ETag: "' . $etag . '"');
        }
        if ($cutarticles) {
            // header("HTTP/1.1 226 IM Used");
            // This should be used as opposed to 200, but Apache doesn't like it.
            // http://intertwingly.net/blog/2004/09/11/Vary-ETag/ says that the
            // status code should be 200.
            header("Cache-Control: no-store, im");
            header("IM: feed");
        }
    }
    $out = array_merge($out, $articles);
    header('Content-type: application/atom+xml; charset=utf-8');
    return chr(60) . '?xml version="1.0" encoding="UTF-8"?' . chr(62) . n . '<feed xml:lang="' . txpspecialchars($language) . '" xmlns="http://www.w3.org/2005/Atom">' . join(n, $out) . '</feed>';
}
Esempio n. 5
0
function rss()
{
    global $prefs, $thisarticle;
    extract($prefs);
    extract(doSlash(gpsa(array('category', 'section', 'limit', 'area'))));
    $area = gps('area');
    $sitename .= $section ? ' - ' . $section : '';
    $sitename .= $category ? ' - ' . $category : '';
    $dn = explode('/', $siteurl);
    $mail_or_domain = $use_mail_on_feeds_id ? eE($blog_mail_uid) : $dn[0];
    $out[] = tag('http://textpattern.com/?v=' . $version, 'generator');
    $out[] = tag(doSpecial($sitename), 'title');
    $out[] = tag(hu, 'link');
    $out[] = tag(doSpecial($site_slogan), 'description');
    $last = fetch('unix_timestamp(val)', 'txp_prefs', 'name', 'lastmod');
    $out[] = tag(safe_strftime('rfc822', $last), 'pubDate');
    $articles = array();
    if (!$area or $area == 'article') {
        $sfilter = $section ? "and Section = '" . $section . "'" : '';
        $cfilter = $category ? "and (Category1='" . $category . "' or Category2='" . $category . "')" : '';
        $limit = $limit ? $limit : $rss_how_many;
        $limit = intval(min($limit, max(100, $rss_how_many)));
        $frs = safe_column("name", "txp_section", "in_rss != '1'");
        if ($frs) {
            foreach ($frs as $f) {
                $query[] = "and Section != '" . doSlash($f) . "'";
            }
        }
        $query[] = $sfilter;
        $query[] = $cfilter;
        $rs = safe_rows_start("*, unix_timestamp(Posted) as uPosted, ID as thisid", "textpattern", "Status = 4 " . join(' ', $query) . "and Posted < now() order by Posted desc limit {$limit}");
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                populateArticleData($a);
                $cb = callback_event('rss_entry');
                $a['posted'] = $uPosted;
                $permlink = permlinkurl($a);
                $summary = trim(replace_relative_urls(parse($thisarticle['excerpt']), $permlink));
                $content = trim(replace_relative_urls(parse($thisarticle['body']), $permlink));
                if ($syndicate_body_or_excerpt) {
                    # short feed: use body as summary if there's no excerpt
                    if (!trim($summary)) {
                        $summary = $content;
                    }
                    $content = '';
                }
                if ($show_comment_count_in_feed) {
                    $count = $comments_count > 0 ? ' [' . $comments_count . ']' : '';
                } else {
                    $count = '';
                }
                $Title = escape_output(strip_tags($Title)) . $count;
                $thisauthor = get_author_name($AuthorID);
                $item = tag($Title, 'title') . n . (trim($summary) ? tag(n . escape_cdata($summary) . n, 'description') . n : '') . (trim($content) ? tag(n . escape_cdata($content) . n, 'content:encoded') . n : '') . tag($permlink, 'link') . n . tag(safe_strftime('rfc822', $a['posted']), 'pubDate') . n . tag(htmlspecialchars($thisauthor), 'dc:creator') . n . tag('tag:' . $mail_or_domain . ',' . $feed_time . ':' . $blog_uid . '/' . $uid, 'guid', ' isPermaLink="false"') . n . $cb;
                $articles[$ID] = tag($item, 'item');
                $etags[$ID] = strtoupper(dechex(crc32($articles[$ID])));
                $dates[$ID] = $uPosted;
            }
        }
    } elseif ($area == 'link') {
        $cfilter = $category ? "category='{$category}'" : '1';
        $limit = $limit ? $limit : $rss_how_many;
        $limit = intval(min($limit, max(100, $rss_how_many)));
        $rs = safe_rows_start("*, unix_timestamp(date) as uDate", "txp_link", "{$cfilter} order by date desc limit {$limit}");
        if ($rs) {
            while ($a = nextRow($rs)) {
                extract($a);
                $item = tag(doSpecial($linkname), 'title') . n . tag(doSpecial($description), 'description') . n . tag(doSpecial($url), 'link') . n . tag(safe_strftime('rfc822', $uDate), 'pubDate');
                $articles[$id] = tag($item, 'item');
                $etags[$id] = strtoupper(dechex(crc32($articles[$id])));
                $dates[$id] = $date;
            }
        }
    }
    //turn on compression if we aren't using it already
    if (extension_loaded('zlib') && ini_get("zlib.output_compression") == 0 && ini_get('output_handler') != 'ob_gzhandler' && !headers_sent()) {
        @ob_start("ob_gzhandler");
    }
    handle_lastmod();
    $hims = serverset('HTTP_IF_MODIFIED_SINCE');
    $imsd = $hims ? strtotime($hims) : 0;
    if (is_callable('apache_request_headers')) {
        $headers = apache_request_headers();
        if (isset($headers["A-IM"])) {
            $canaim = strpos($headers["A-IM"], "feed");
        } else {
            $canaim = false;
        }
    } else {
        $canaim = false;
    }
    $hinm = stripslashes(serverset('HTTP_IF_NONE_MATCH'));
    $cutarticles = false;
    if ($canaim !== false) {
        foreach ($articles as $id => $thing) {
            if (strpos($hinm, $etags[$id]) !== false) {
                unset($articles[$id]);
                $cutarticles = true;
                $cut_etag = true;
            }
            if ($dates[$id] < $imsd) {
                unset($articles[$id]);
                $cutarticles = true;
                $cut_time = true;
            }
        }
    }
    if (isset($cut_etag) && isset($cut_time)) {
        header("Vary: If-None-Match, If-Modified-Since");
    } else {
        if (isset($cut_etag)) {
            header("Vary: If-None-Match");
        } else {
            if (isset($cut_time)) {
                header("Vary: If-Modified-Since");
            }
        }
    }
    $etag = @join("-", $etags);
    if (strstr($hinm, $etag)) {
        header("HTTP/1.1 304 Not Modified");
        exit;
    }
    if ($cutarticles) {
        //header("HTTP/1.1 226 IM Used");
        //This should be used as opposed to 200, but Apache doesn't like it.
        //http://intertwingly.net/blog/2004/09/11/Vary-ETag/ says that the status code should be 200.
        header("Cache-Control: no-store, im");
        header("IM: feed");
    }
    $out = array_merge($out, $articles);
    header("Content-Type: application/rss+xml; charset=utf-8");
    if ($etag) {
        header('ETag: "' . $etag . '"');
    }
    return '<?xml version="1.0" encoding="utf-8"?>' . n . '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">' . n . tag(join(n, $out), 'channel') . n . '</rss>';
}