<?php
/*
* Copyright 2012 Douglas Robbins <hide@address.com>
*
* This file is part of Blite, a blogging application, available at
* <http://blite.ca/>.
*
* Blite is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
require('configure.php');
if ($cfg['enablecomments'] !== '1') {
header("Location: " . $cfg['home']);
}
// Check nonce for admin actions.
if ( !empty($_POST['delete']) || !empty($_POST['spam']) || !empty($_POST['ham']) ) {
list($nonce, $noncestamp, $nonceerror) = verify_nonce('c_admin','The admin page expired.');
if ( !empty($nonceerror) ) {
echo $nonceerror;
exit;
}
}
if (!empty($_POST['delete'])) {
// Delete a comment.
if (!$authuser) {
echo $lang['permdenied'];
exit;
}
$postid = $_POST['threadid'];
$comid = $_POST['commentid'];
if ( is_numeric($postid) && is_numeric($comid) ) {
$query_params = array( 'postid' => 'int' );
db_query("UPDATE posts set comcount=comcount-1 WHERE id=?");
$query_params = array( 'comid' => 'int' );
db_query("DELETE FROM comments WHERE id=?");
}
$query_params = array( 'nonce' => 'txt', 'noncestamp' => 'int' );
db_query("INSERT INTO nonces (nonce, type, stamp) VALUES (?, 'c_admin', ?)");
rm_cache($cfg['datadir'] . '/cache/recent-comments');
header("Location: " . $cfg['home'] . "?t=${postid}#comments");
exit;
}
elseif ( ( !empty($_POST['spam']) || !empty($_POST['ham']) ) && is_numeric($_POST['commentid']) && $cfg['blogspam'] ) {
// blogspam.net training
if (!$authuser) {
echo $lang['permdenied'];
exit;
}
$comid = $_POST['commentid'];
$query_params = array( 'comid' => 'int' );
$results = db_query("SELECT id, ip, name, email, comment, web FROM comments WHERE id=?");
$row = db_getdata($results);
$ip = $row['ip'];
$name = $row['name'];
$email = $row['email'];
$web = $row['web'];
$comment = $row['comment'];
if (!empty($_POST['spam'])) {
$traintype = 'spam';
}
elseif (!empty($_POST['ham'])) {
$traintype = 'ok';
}
if ( !empty($traintype) && !empty($row['id']) ) {
$params = array (
"ip" => $ip,
"email" => $email,
"link" => $web,
"name" => $name,
"comment" => $comment,
"site" => $cfg['home'],
"options" => "min-words=1,exclude=rdns,exclude=bayesian",
"train" => $traintype
);
$result = blogspam_train($params);
if ($result == 'OK') {
$query_params = array( 'traintype' => 'txt' );
db_query("UPDATE training set msgcount=msgcount+1 WHERE traintype=?");
}
$query_params = array( 'nonce' => 'txt', 'noncestamp' => 'int' );
db_query("INSERT INTO nonces (nonce, type, stamp) VALUES (?, 'c_admin', ?)");
$page['title'] = "BlogSpam.net Training";
$page['redirect'] = "<meta http-equiv='refresh' content='2;" . $_SESSION['lastpage'] . "'>";
$page['msg'] = "<b>BlogSpam.net Training</b><br>\n$result";
$template = file_get_contents('themes/' . $cfg['theme'] . '/templates/message.tpl');
foreach ($page as $key => $val) {
$template = str_replace("#${key}#",$val,$template);
}
echo $template;
exit;
}
}
elseif ($_POST['submit']) {
// Post a new or edited comment.
$errors = array();
// Check the nonce.
list($nonce, $noncestamp, $nonceerror) = verify_nonce('comment','The comment form expired.');
if ( !empty($nonceerror) ) {
$errors[] = $nonceerror;
}
if (is_numeric($_POST['postid'])) {
$postid = $_POST['postid'];
}
else {
$errors[] = "Missing post id.";
}
if ($errors && !$authuser) {
// Unset any comment form session vars.
if ($_SESSION['com_name']) {
unset($_SESSION['com_name']);
}
if ($_SESSION['com_email']) {
unset($_SESSION['com_email']);
}
if ($_SESSION['com_web']) {
unset($_SESSION['com_web']);
}
}
else {
// If no postid or nonce error, process the submitted data.
$name = clean_comment($_POST['name'], 1);
$email = clean_comment($_POST['email'], 1);
if ($_POST['web'] && substr($_POST['web'], 0,7) !== 'http://' && (substr($_POST['web'], 0,8) !== 'https://') ) {
$_POST['web'] = 'http://' . $_POST['web'];
}
$web = clean_comment($_POST['web'], 1);
$comment = clean_comment($_POST['comment'], 2);
$ip = $_SERVER['REMOTE_ADDR'];
if (!$authuser) {
$_SESSION['com_name'] = $name;
$_SESSION['com_email'] = $email;
}
$_SESSION['com_web'] = $web;
if (is_numeric($_POST['comid'])) {
$comid = $_POST['comid'];
}
$now = time();
if (!$name) {
$errors[] = $lang['namereq'];
}
elseif ($cfg['protectadmin'] && !$authuser && $name == $cfg['adminname']) {
$errors[] = $lang['namerestr'];
}
if ($cfg['protectadmin'] && !$authuser && $email == $cfg['adminmail']) {
$errors[] = $lang['emailrestr'];
}
elseif ($email && !valid_email($email)) {
$errors[] = $lang['emailinvalid'];
}
elseif (!$email) {
$errors[] = $lang['emailreq'];
}
if (!$comment) {
$errors[] = $lang['commentreq'];
}
}
// If we haven't encountered an error, submit to blogspam.net if enabled.
if (empty($errors) && $cfg['blogspam'] == 1) {
// Check the training counts to see if we should use bayes analysis.
$query_params = '';
$results = db_query("SELECT * FROM training");
$queries++;
while ($row = db_getdata($results)) {
$cntname = $row['traintype'] . 'count';
${$cntname} = $row['msgcount'];
}
if ( $cfg['minbayesok'] > 0 && $okcount < $cfg['minbayesok'] && $cfg['minbayesspam'] > 0 && $spamcount < $cfg['minbayesspam'] ) {
$excludebayes = ',exclude=bayesian';
}
$params = array (
"ip" => $ip,
"email" => $email,
"link" => $web,
"name" => $name,
"comment" => $comment,
"site" => $cfg['home'],
"options" => "min-words=1,exclude=rdns${excludebayes}"
);
$spam = blogspam_check($params);
if ($spam) {
$errors[] = 'blogspam.net says: <b>' . str_replace(':', ': ', $spam) . '</b>. ' . $lang['blogspampos'];
// Save the message in the spam table.
$query_params = array (
'spam' => 'txt',
'postid' => 'int',
'now' => 'int',
'ip' => 'txt',
'name' => 'txt',
'email' => 'txt',
'comment' => 'txt',
'web' => 'txt'
);
db_query("INSERT INTO spam (analysis, postid, stamp, ip, name, email, comment, web) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
}
}
if (!empty($errors)) {
$cnt = count($errors);
$eword = 'Errors';
if ($cnt == 1) {
$eword = 'Error';
}
foreach ($errors as $key => $val) {
$error .= $val . ' ';
}
$error = "\n<div class='com_error'><b>$cnt $eword:</b> $error</div>\n";
// Redisplay the message text for any error other than spam:
if (!$spam) {
$_SESSION['com_comment'] = $comment;
}
$_SESSION['com_error'] = $error;
header("Location: ./?t=$postid#commentform");
}
else {
// Proceed to store the comment.
if ($_SESSION['com_comment']) {
unset ($_SESSION['com_comment']);
}
if ($comid) {
// Editing a comment.
if (!$authuser) {
$query_params = array( 'comid' => 'int' );
$results = db_query("SELECT stamp, email, ip FROM comments WHERE id=?");
$queries++;
$row = db_getdata($results);
$cookiename = 'comment-' . $comid;
$good_val = sha1 ($row['email'] . $row['ip'] . $_SERVER['HTTP_USER_AGENT']);
$expired = false;
if ( $row['stamp'] < time() - ($cfg['editfor'] * 60) ) {
$expired = true;
}
}
// Check the cookie.
if ( (isset($_COOKIE[$cookiename]) && !empty($good_val) && $_COOKIE[$cookiename] == $good_val && $_SERVER['REMOTE_ADDR'] == $row['ip'] && !$expired ) || $authuser ) {
$query_params = array (
'name' => 'txt',
'email' => 'txt',
'comment' => 'txt',
'web' => 'txt',
'comid' => 'int'
);
db_query("UPDATE comments set name=?, email=?, comment=?, web=? WHERE id=?");
// Expire the cookie.
setcookie($cookiename, '', 1);
// Send 'comment edited' message to admin.
if ($cfg['adminmail']) {
$msg_subject = 'Comment edited at ' . strip_tags($cfg['sitename']);
$msg_to = $cfg['adminmail'];
$msg_body = "Name: $name\n";
$msg_body .= "Email: $email\n";
$msg_body .= "Website: $web\n\n";
$msg_body .= $comment;
$msg_body .= "\n\n" . $cfg['home'] . "?t=$postid#comment-$comid";
$msg_fromname = $cfg['sitename'] . ' Website';
$msg_fromaddress = $cfg['adminmail'];
mail ($msg_to, $msg_subject, $msg_body, "From: $msg_fromname <${msg_fromaddress}>", "-f $msg_fromaddress");
}
}
}
else {
// New comment.
$query_params = array (
'postid' => 'int',
'now' => 'int',
'ip' => 'txt',
'name' => 'txt',
'email' => 'txt',
'comment' => 'txt',
'web' => 'txt'
);
db_query("INSERT INTO comments (postid, stamp, ip, name, email, comment, web) VALUES (?, ?, ?, ?, ?, ?, ?)");
$comid = $db->lastInsertRowID();
$query_params = array ( 'postid' => 'int' );
db_query("UPDATE posts set comcount=comcount+1 WHERE id=?");
// Set cookie for editing.
$str = 'comment-' . $comid;
$val = sha1 ($email . $ip . $_SERVER['HTTP_USER_AGENT']);
$expire = $now + ($cfg['editfor'] * 60);
setcookie($str, $val, $expire);
// Set or update the guest's name, mail, web cookies.
// 90 day expiry.
if (!$authuser) {
$expire = $now + 7776000;
$idstr = sha1($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
setcookie('guest_name_'.$idstr, $name, $expire, '', '');
setcookie('guest_email_'.$idstr, $email, $expire, '', '');
if (!empty($web)) {
setcookie('guest_web_'.$idstr, $web, $expire, '', '');
}
}
// Send 'new comment' message to admin.
if ($cfg['adminmail']) {
$msg_subject = 'New comment at ' . strip_tags($cfg['sitename']);
$msg_to = $cfg['adminmail'];
$msg_body = "Name: $name\n";
$msg_body .= "Email: $email\n";
$msg_body .= "Website: $web\n\n";
$msg_body .= $comment;
$msg_body .= "\n\n" . $cfg['home'] . "?t=$postid#comment-$comid";
$msg_fromname = $cfg['sitename'] . ' Website';
$msg_fromaddress = $cfg['adminmail'];
mail ($msg_to, $msg_subject, $msg_body, "From: $msg_fromname <${msg_fromaddress}>", "-f $msg_fromaddress");
}
}
$query_params = array( 'nonce' => 'txt', 'noncestamp' => 'int' );
db_query("INSERT INTO nonces (nonce, type, stamp) VALUES (?, 'comment', ?)");
rm_cache($cfg['datadir'] . '/cache/recent-comments');
header("Location: ./?t=$postid#comment-$comid");
}
}
else {
header("Location: ./");
}
exit;
function clean_comment($text, $type) {
global $cfg;
global $php_allowedtags;
global $_POST;
if ($type == '1') {
$goodtags = '';
$maxlength = 80;
}
else {
$goodtags = $php_allowedtags;
$maxlength = $cfg['maxcommentlength'];
}
$text = trim($text);
if (get_magic_quotes_gpc()) {
$text = stripslashes($text);
}
if ( strlen($text) > $maxlength ) {
$text = substr($text, 0, $maxlength);
}
if ($type == '2') {
$text = str_replace(array("\r\n", "\r"), "\n", $text);
// Replace entities within <code> tags
if (stristr($text, '<code>')) {
$text = encode_code($text);
}
$text = trim(strip_tags($text, $goodtags));
if (stristr($text, '<')) {
// Remove tag attributes.
$text = strip_attributes($text);
// Run strip_tags again to remove doctype & body tags added by
// php dom in strip_attributes().
$text = trim(strip_tags($text, $goodtags));
}
}
$text = trim($text);
return $text;
}
function strip_attributes($str) {
global $cfg;
$dom = new DOMDocument();
$dom->loadHTML($str);
foreach ($cfg['allowedtags'] as $tag) {
$a = $dom->getElementsByTagName($tag)->item(0);
if ($a && $a->hasAttributes()) {
foreach ($a->attributes as $attr) {
$name = $attr->nodeName;
if ($name !== "href") {
$bad[] = $name;
}
else {
$val = $attr->nodeValue;
if (stristr($val, 'javascript:')) {
$bad[] = $name;
}
}
}
if ($bad) {
foreach ($bad as $att) {
$a->removeAttribute($att);
}
}
}
if ($a && $tag == 'a' && $cfg['linksnofollow']) {
$a->setAttribute("rel", "nofollow");
}
if ($a && $tag == 'a' && $cfg['linksnewwindow']) {
$a->setAttribute("target", "_blank");
}
unset($bad);
unset($a);
}
return $dom->saveHTML();
}
function blogspam_check($params) {
$blogspam_request = xmlrpc_encode_request("testComment", $params);
$fp = fsockopen("test.blogspam.net", 8888, $errno, $errstr, 5);
if ($fp) {
$send = "POST / HTTP/1.1\r\n";
$send .= "Host: test.blogspam.net\r\n";
$send .= "Connection: close\r\n";
$send .= "Content-Type: text/xml\r\n";
$send .= "Content-Length: " . strlen($blogspam_request) . "\r\n\r\n";
$send .= $blogspam_request;
fwrite($fp, $send);
stream_set_timeout($fp, 5);
while (!feof($fp)) {
$blogspam_response .= fread($fp, 8192);
}
fclose($fp);
}
if ($blogspam_response) {
list($headers, $xmlbody) = explode("\r\n\r\n", $blogspam_response);
$method = null;
$response = xmlrpc_decode($xmlbody);
}
if (substr($response, 0, 4) == 'SPAM') {
return $response;
}
}
function blogspam_train($params) {
$blogspam_response = '';
$blogspam_request = xmlrpc_encode_request("testComment", $params);
$fp = fsockopen("test.blogspam.net", 8888, $errno, $errstr, 5);
if ($fp) {
$send = "POST / HTTP/1.1\r\n";
$send .= "Host: test.blogspam.net\r\n";
$send .= "Connection: close\r\n";
$send .= "Content-Type: text/xml\r\n";
$send .= "Content-Length: " . strlen($blogspam_request) . "\r\n\r\n";
$send .= $blogspam_request;
fwrite($fp, $send);
stream_set_timeout($fp, 5);
while (!feof($fp)) {
$blogspam_response .= fread($fp, 8192);
}
fclose($fp);
}
if (!empty($blogspam_response)) {
list($headers, $xmlbody) = explode("\r\n\r\n", $blogspam_response);
$method = null;
$response = xmlrpc_decode($xmlbody);
}
return $response;
}
?>