/** * 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).*)=/", "&\\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>'; }
function doArticles($atts, $iscustom, $thing = null) { global $pretext, $prefs; extract($pretext); extract($prefs); $customFields = getCustomFields(); $customlAtts = array_null(array_flip($customFields)); if ($iscustom) { $extralAtts = array('category' => '', 'section' => '', 'excerpted' => '', 'author' => '', 'month' => '', 'expired' => $publish_expired_articles, 'id' => '', 'exclude' => ''); } else { $extralAtts = array('listform' => '', 'searchform' => '', 'searchall' => 1, 'searchsticky' => 0, 'pageby' => '', 'pgonly' => 0); } // Getting attributes. $theAtts = lAtts(array('form' => 'default', 'limit' => 10, 'sort' => '', 'sortby' => '', 'sortdir' => '', 'keywords' => '', 'time' => 'past', 'status' => STATUS_LIVE, 'allowoverride' => !$q and !$iscustom, 'offset' => 0, 'wraptag' => '', 'break' => '', 'label' => '', 'labeltag' => '', 'class' => '') + $customlAtts + $extralAtts, $atts); // For the txp:article tag, some attributes are taken from globals; // override them, then stash all filter attributes. if (!$iscustom) { $theAtts['category'] = $c ? $c : ''; $theAtts['section'] = $s && $s != 'default' ? $s : ''; $theAtts['author'] = !empty($author) ? $author : ''; $theAtts['month'] = !empty($month) ? $month : ''; $theAtts['frontpage'] = $s && $s == 'default' ? true : false; $theAtts['excerpted'] = 0; $theAtts['exclude'] = 0; $theAtts['expired'] = $publish_expired_articles; filterAtts($theAtts); } else { $theAtts['frontpage'] = false; } extract($theAtts); // If a listform is specified, $thing is for doArticle() - hence ignore here. if (!empty($listform)) { $thing = ''; } $pageby = empty($pageby) ? $limit : $pageby; // Treat sticky articles differently wrt search filtering, etc. $status = in_array(strtolower($status), array('sticky', STATUS_STICKY)) ? STATUS_STICKY : STATUS_LIVE; $issticky = $status == STATUS_STICKY; // Give control to search, if necessary. if ($q && !$iscustom && !$issticky) { include_once txpath . '/publish/search.php'; $s_filter = $searchall ? filterSearch() : ''; $q = trim($q); $quoted = $q[0] === '"' && $q[strlen($q) - 1] === '"'; $q = doSlash($quoted ? trim(trim($q, '"')) : $q); // Searchable article fields are limited to the columns of the // textpattern table and a matching fulltext index must exist. $cols = do_list_unique($searchable_article_fields); if (empty($cols) or $cols[0] == '') { $cols = array('Title', 'Body'); } $match = ", MATCH (`" . join("`, `", $cols) . "`) AGAINST ('{$q}') AS score"; $search_terms = preg_replace('/\\s+/', ' ', str_replace(array('\\', '%', '_', '\''), array('\\\\', '\\%', '\\_', '\\\''), $q)); if ($quoted || empty($m) || $m === 'exact') { for ($i = 0; $i < count($cols); $i++) { $cols[$i] = "`{$cols[$i]}` LIKE '%{$search_terms}%'"; } } else { $colJoin = $m === 'any' ? "OR" : "AND"; $search_terms = explode(' ', $search_terms); for ($i = 0; $i < count($cols); $i++) { $like = array(); foreach ($search_terms as $search_term) { $like[] = "`{$cols[$i]}` LIKE '%{$search_term}%'"; } $cols[$i] = "(" . join(" {$colJoin} ", $like) . ")"; } } $cols = join(" OR ", $cols); $search = " AND ({$cols}) {$s_filter}"; // searchall=0 can be used to show search results for the current // section only. if ($searchall) { $section = ''; } if (!$sort) { $sort = "score DESC"; } } else { $match = $search = ''; if (!$sort) { $sort = "Posted DESC"; } } // For backwards compatibility. sortby and sortdir are deprecated. if ($sortby) { trigger_error(gTxt('deprecated_attribute', array('{name}' => 'sortby')), E_USER_NOTICE); if (!$sortdir) { $sortdir = "DESC"; } else { trigger_error(gTxt('deprecated_attribute', array('{name}' => 'sortdir')), E_USER_NOTICE); } $sort = "{$sortby} {$sortdir}"; } elseif ($sortdir) { trigger_error(gTxt('deprecated_attribute', array('{name}' => 'sortdir')), E_USER_NOTICE); $sort = "Posted {$sortdir}"; } // Building query parts. $frontpage = ($frontpage and (!$q or $issticky)) ? filterFrontPage() : ''; $category = join("','", doSlash(do_list_unique($category))); $category = !$category ? '' : " AND (Category1 IN ('" . $category . "') OR Category2 IN ('" . $category . "'))"; $section = !$section ? '' : " AND Section IN ('" . join("','", doSlash(do_list_unique($section))) . "')"; $excerpted = !$excerpted ? '' : " AND Excerpt !=''"; $author = !$author ? '' : " AND AuthorID IN ('" . join("','", doSlash(do_list_unique($author))) . "')"; $month = !$month ? '' : " AND Posted LIKE '" . doSlash($month) . "%'"; $ids = $id ? array_map('intval', do_list_unique($id)) : array(); $exclude = $exclude ? array_map('intval', do_list_unique($exclude)) : array(); $id = (!$id ? '' : " AND ID IN (" . join(',', $ids) . ")") . (!$exclude ? '' : " AND ID NOT IN (" . join(',', $exclude) . ")"); switch ($time) { case 'any': $time = ""; break; case 'future': $time = " AND Posted > " . now('posted'); break; default: $time = " AND Posted <= " . now('posted'); } if (!$expired) { $time .= " AND (" . now('expires') . " <= Expires OR Expires = " . NULLDATETIME . ")"; } $custom = ''; if ($customFields) { foreach ($customFields as $cField) { if (isset($atts[$cField])) { $customPairs[$cField] = $atts[$cField]; } } if (!empty($customPairs)) { $custom = buildCustomSql($customFields, $customPairs); } } // Allow keywords for no-custom articles. That tagging mode, you know. if ($keywords) { $keys = doSlash(do_list_unique($keywords)); foreach ($keys as $key) { $keyparts[] = "FIND_IN_SET('" . $key . "', Keywords)"; } $keywords = " AND (" . join(' or ', $keyparts) . ")"; } if ($q and $searchsticky) { $statusq = " AND Status >= " . STATUS_LIVE; } elseif ($id) { $statusq = " AND Status >= " . STATUS_LIVE; } else { $statusq = " AND Status = " . intval($status); } $where = "1 = 1" . $statusq . $time . $search . $id . $category . $section . $excerpted . $month . $author . $keywords . $custom . $frontpage; // Do not paginate if we are on a custom list. if (!$iscustom and !$issticky) { $grand_total = safe_count('textpattern', $where); $total = $grand_total - $offset; $numPages = ceil($total / $pageby); $pg = !$pg ? 1 : $pg; $pgoffset = $offset + ($pg - 1) * $pageby; // Send paging info to txp:newer and txp:older. $pageout['pg'] = $pg; $pageout['numPages'] = $numPages; $pageout['s'] = $s; $pageout['c'] = $c; $pageout['context'] = 'article'; $pageout['grand_total'] = $grand_total; $pageout['total'] = $total; global $thispage; if (empty($thispage)) { $thispage = $pageout; } if ($pgonly) { return; } } else { $pgoffset = $offset; } // Preserve order of custom article ids unless 'sort' attribute is set. if (!empty($atts['id']) && empty($atts['sort'])) { $safe_sort = "FIELD(id, " . join(',', $ids) . ")"; } else { $safe_sort = doSlash($sort); } $rs = safe_rows_start("*, UNIX_TIMESTAMP(Posted) AS uPosted, UNIX_TIMESTAMP(Expires) AS uExpires, UNIX_TIMESTAMP(LastMod) AS uLastMod" . $match, 'textpattern', "{$where} ORDER BY {$safe_sort} LIMIT " . intval($pgoffset) . ", " . intval($limit)); // Get the form name. if ($q and !$iscustom and !$issticky) { $fname = $searchform ? $searchform : 'search_results'; } else { $fname = !empty($listform) ? $listform : $form; } if ($rs) { $count = 0; $last = numRows($rs); $articles = array(); while ($a = nextRow($rs)) { ++$count; populateArticleData($a); global $thisarticle, $uPosted, $limit; $thisarticle['is_first'] = $count == 1; $thisarticle['is_last'] = $count == $last; // Article form preview. if (txpinterface === 'admin' && ps('Form')) { doAuth(); if (!has_privs('form')) { txp_status_header('401 Unauthorized'); exit(hed('401 Unauthorized', 1) . graf(gTxt('restricted_area'))); } $articles[] = parse(gps('Form')); } elseif ($allowoverride and $a['override_form']) { $articles[] = parse_form($a['override_form']); } else { $articles[] = $thing ? parse($thing) : parse_form($fname); } // Sending these to paging_link(); Required? $uPosted = $a['uPosted']; unset($GLOBALS['thisarticle']); } return doLabel($label, $labeltag) . doWrap($articles, $wraptag, $break, $class); } }
/** * Generates and returns an RSS feed. * * This function can only be called once on a page. It send HTTP * headers and returns an RSS feed based on the requested URL parameters. * Accepts HTTP GET parameters 'limit', 'area', 'section' and 'category'. * * @return string XML */ 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(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) : ''; $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') . " <= 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('posted') . $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; $a['expires'] = $uExpires; $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"); } 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 ($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>'; }
/** * Checks if an IP is on a spam blacklist. * * @param string $ip The IP address * @param string|array $checks The checked lists. Defaults to 'spam_blacklists' preferences string * @return string|bool The lists the IP is on or FALSE * @package Comment * @example * if (is_blacklisted('127.0.0.1')) * { * echo "'127.0.0.1' is blacklisted."; * } */ function is_blacklisted($ip, $checks = '') { if (!$checks) { $checks = do_list_unique(get_pref('spam_blacklists')); } $rip = join('.', array_reverse(explode('.', $ip))); foreach ((array) $checks as $a) { $parts = explode(':', $a, 2); $rbl = $parts[0]; if (isset($parts[1])) { foreach (explode(':', $parts[1]) as $code) { $codes[] = strpos($code, '.') ? $code : '127.0.0.' . $code; } } $hosts = $rbl ? @gethostbynamel($rip . '.' . trim($rbl, '. ') . '.') : false; if ($hosts and (!isset($codes) or array_intersect($hosts, $codes))) { $listed[] = $rbl; } } return !empty($listed) ? join(', ', $listed) : false; }
/** * Locks a table. * * The $table argument accepts comma-separated list of table names, if you need * to lock multiple tables at once. * * @param string $table The table * @param string $type The lock type * @param bool $debug Dump the query * @return bool TRUE if the tables are locked * @since 4.6.0 * @example * if (safe_lock('myTable')) * { * echo "'myTable' is 'write' locked."; * } */ function safe_lock($table, $type = 'write', $debug = false) { return (bool) safe_query("LOCK TABLES " . join(' ' . $type . ', ', doArray(do_list_unique($table), 'safe_pfx')) . ' ' . $type, $debug); }
function file_download_list($atts, $thing = null) { global $s, $c, $context, $thisfile, $thispage, $pretext; extract(lAtts(array('break' => br, 'category' => '', 'author' => '', 'realname' => '', 'auto_detect' => 'category, author', 'class' => __FUNCTION__, 'form' => 'files', 'id' => '', 'label' => '', 'labeltag' => '', 'pageby' => '', 'limit' => 10, 'offset' => 0, 'sort' => 'filename asc', 'wraptag' => '', 'status' => STATUS_LIVE), $atts)); if (!is_numeric($status)) { $status = getStatusNum($status); } // Note: status treated slightly differently. $where = $statwhere = array(); $filters = isset($atts['id']) || isset($atts['category']) || isset($atts['author']) || isset($atts['realname']) || isset($atts['status']); $context_list = empty($auto_detect) || $filters ? array() : do_list_unique($auto_detect); $pageby = $pageby == 'limit' ? $limit : $pageby; if ($category) { $where[] = "category IN ('" . join("','", doSlash(do_list_unique($category))) . "')"; } $ids = array_map('intval', do_list_unique($id)); if ($id) { $where[] = "id IN ('" . join("','", $ids) . "')"; } if ($status) { $statwhere[] = "status = '" . doSlash($status) . "'"; } if ($author) { $where[] = "author IN ('" . join("','", doSlash(do_list_unique($author))) . "')"; } if ($realname) { $authorlist = safe_column("name", 'txp_users', "RealName IN ('" . join("','", doArray(doSlash(do_list_unique($realname)), 'urldecode')) . "')"); if ($authorlist) { $where[] = "author IN ('" . join("','", doSlash($authorlist)) . "')"; } } // If no files are selected, try... if (!$where && !$filters) { foreach ($context_list as $ctxt) { switch ($ctxt) { case 'category': // ...the global category in the URL. if ($context == 'file' && !empty($c)) { $where[] = "category = '" . doSlash($c) . "'"; } break; case 'author': // ...the global author in the URL. if ($context == 'file' && !empty($pretext['author'])) { $where[] = "author = '" . doSlash($pretext['author']) . "'"; } break; } // Only one context can be processed. if ($where) { break; } } } if (!$where && !$statwhere && $filters) { // If nothing matches, output nothing. return ''; } $where[] = "created <= " . now('created'); $where = join(" AND ", array_merge($where, $statwhere)); // Set up paging if required. if ($limit && $pageby) { $grand_total = safe_count('txp_file', $where); $total = $grand_total - $offset; $numPages = $pageby > 0 ? ceil($total / $pageby) : 1; $pg = !$pretext['pg'] ? 1 : $pretext['pg']; $pgoffset = $offset + ($pg - 1) * $pageby; // Send paging info to txp:newer and txp:older. $pageout['pg'] = $pg; $pageout['numPages'] = $numPages; $pageout['s'] = $s; $pageout['c'] = $c; $pageout['context'] = 'file'; $pageout['grand_total'] = $grand_total; $pageout['total'] = $total; if (empty($thispage)) { $thispage = $pageout; } } else { $pgoffset = $offset; } // Preserve order of custom file ids unless 'sort' attribute is set. if (!empty($atts['id']) && empty($atts['sort'])) { $safe_sort = "FIELD(id, " . join(',', $ids) . ")"; } else { $safe_sort = doSlash($sort); } $qparts = array("ORDER BY " . $safe_sort, $limit ? "LIMIT " . intval($pgoffset) . ", " . intval($limit) : ''); $rs = safe_rows_start("*", 'txp_file', $where . ' ' . join(' ', $qparts)); if ($rs) { $count = 0; $last = numRows($rs); $out = array(); while ($a = nextRow($rs)) { ++$count; $thisfile = file_download_format_info($a); $thisfile['is_first'] = $count == 1; $thisfile['is_last'] = $count == $last; $out[] = $thing ? parse($thing) : parse_form($form); $thisfile = ''; } if ($out) { return doLabel($label, $labeltag) . doWrap($out, $wraptag, $break, $class); } } return ''; }