# HG changeset patch # User Dan # Date 1232936285 18000 # Node ID 9d5c04c1414fb8c7279d14540a463ee3c7db1f96 # Parent 880c4b7eb65876ce218b9375ef143cfb80aa836a Added (very basic) spam filtering plugin support. Plugins can mark a message as spam by hooking into the spam check API, which is documented in functions.php. No spam checking functionality is built-in. diff -r 880c4b7eb658 -r 9d5c04c1414f includes/clientside/static/comments.js --- a/includes/clientside/static/comments.js Sat Jan 17 15:16:36 2009 -0500 +++ b/includes/clientside/static/comments.js Sun Jan 25 21:18:05 2009 -0500 @@ -54,7 +54,8 @@ materializeComment(response); break; case 'error': - new MessageBox(MB_OK|MB_ICONSTOP, ( response.title ? response.title : 'Error fetching comment data' ), response.error); + load_component(['messagebox', 'fadefilter', 'flyin']); + new MessageBox(MB_OK|MB_ICONSTOP, ( response.title ? response.title : $lang.get('comment_ajax_err_generic_title') ), response.error); break; default: alert(ajax.responseText); @@ -180,8 +181,10 @@ tplvars.DATA = this_comment.comment_data; tplvars.SIGNATURE = this_comment.signature; - if ( this_comment.approved != '1' ) + if ( this_comment.approved == '0' ) tplvars.SUBJECT += ' ' + $lang.get('comment_msg_note_unapp') + ''; + else if ( this_comment.approved == '2' ) + tplvars.SUBJECT += ' ' + $lang.get('comment_msg_note_spam') + ''; // Name tplvars.NAME = this_comment.name; diff -r 880c4b7eb658 -r 9d5c04c1414f includes/comment.php --- a/includes/comment.php Sat Jan 17 15:16:36 2009 -0500 +++ b/includes/comment.php Sun Jan 25 21:18:05 2009 -0500 @@ -123,7 +123,7 @@ $count_total++; ( $row['approved'] == 1 ) ? $count_appr++ : $count_unappr++; - if ( !$this->perms->get_permissions('mod_comments') && $row['approved'] == 0 ) + if ( !$this->perms->get_permissions('mod_comments') && $row['approved'] != COMMENT_APPROVED ) continue; // Localize the rank @@ -142,7 +142,7 @@
-Post from foe hidden. Display post
+' . $lang->get('comment_msg_foe_comment_hidden') . ' ' . $lang->get('comment_btn_display_foe_comment') . '
'; $row['comment_data'] = $wrapper; } @@ -193,7 +193,7 @@ break; case 'edit': $cid = (string)$data['id']; - if ( !preg_match('#^([0-9]+)$#i', $cid) || intval($cid) < 1 ) + if ( !ctype_digit($cid) || intval($cid) < 1 ) { echo '{"mode":"error","error":"HACKING ATTEMPT"}'; return false; @@ -228,7 +228,7 @@ break; case 'delete': $cid = (string)$data['id']; - if ( !preg_match('#^([0-9]+)$#i', $cid) || intval($cid) < 1 ) + if ( !ctype_digit($cid) || intval($cid) < 1 ) { echo '{"mode":"error","error":"HACKING ATTEMPT"}'; return false; @@ -266,17 +266,28 @@ // Guest authorization if ( getConfig('comments_need_login') == '2' && !$session->user_logged_in ) - $errors[] = 'You need to log in before posting comments.'; + $errors[] = $lang->get('comment_err_need_login'); // CAPTCHA code if ( getConfig('comments_need_login') == '1' && !$session->user_logged_in ) { $real_code = $session->get_captcha($data['captcha_id']); - if ( strtolower($real_code) != strtolower($data['captcha_code']) ) - $errors[] = 'The confirmation code you entered was incorrect.'; + if ( strtolower($real_code) !== strtolower($data['captcha_code']) ) + $errors[] = $lang->get('comment_err_captcha_wrong'); $session->kill_captcha(); } + // Spam check + $spam_policy = getConfig('comment_spam_policy', 'moderate'); + $sc_name = ( $session->user_logged_in ) ? $session->username : $data['name']; + $sc_mail = ( $session->user_logged_in ) ? $session->email : false; + $sc_url = ( $session->user_logged_in ) ? $session->user_extra['user_homepage'] : false; + $spamcheck = $spam_policy === 'accept' ? true : spamalyze($data['text'], $sc_name, $sc_mail, $sc_url); + if ( !$spamcheck && $spam_policy === 'reject' ) + { + $errors[] = $lang->get('comment_err_spamcheck_failed_rejected'); + } + if ( count($errors) > 0 ) { $ret = Array( @@ -295,7 +306,9 @@ $src = $text; $sql_text = $db->escape($text); $text = RenderMan::render($text); - $appr = ( getConfig('approve_comments') == '1' ) ? '0' : '1'; + $appr = ( getConfig('approve_comments') == '1' ) ? COMMENT_UNAPPROVED : COMMENT_APPROVED; + if ( $appr === COMMENT_APPROVED && $spam_policy === 'moderate' && !$spamcheck ) + $appr = COMMENT_SPAM; $time = time(); $date = enano_date('F d, Y h:i a', $time); $ip = $_SERVER['REMOTE_ADDR']; @@ -358,7 +371,7 @@ } $cid = (string)$data['id']; - if ( !preg_match('#^([0-9]+)$#i', $cid) || intval($cid) < 1 ) + if ( !ctype_digit($cid) || intval($cid) < 1 ) { echo '{"mode":"error","error":"HACKING ATTEMPT"}'; return false; diff -r 880c4b7eb658 -r 9d5c04c1414f includes/constants.php --- a/includes/constants.php Sat Jan 17 15:16:36 2009 -0500 +++ b/includes/constants.php Sun Jan 25 21:18:05 2009 -0500 @@ -67,6 +67,11 @@ define('PAGE_GRP_NORMAL', 3); define('PAGE_GRP_REGEX', 4); +// Comment types +define('COMMENT_APPROVED', 1); +define('COMMENT_UNAPPROVED', 0); +define('COMMENT_SPAM', 2); + // Session key types // Short keys last for getConfig('session_short_time', '720'); in minutes and auto-renew. // Long keys last for getConfig('session_remember_time', '30'); in days and do NOT auto-renew. diff -r 880c4b7eb658 -r 9d5c04c1414f includes/functions.php --- a/includes/functions.php Sat Jan 17 15:16:36 2009 -0500 +++ b/includes/functions.php Sun Jan 25 21:18:05 2009 -0500 @@ -2164,6 +2164,46 @@ } /** + * Portal function allowing spam-filtering plugins. + * Hooking guide: + * - Attach to spam_check + * - Return either true or false - true if the message is spam-free, false if it fails your test + * @example +
+ $plugins->attachHook('spam_check', 'return my_spam_check($string);');
+ function my_spam_check($string)
+ {
+ if ( stristr($string, 'viagra') )
+ return false;
+
+ return true;
+ }
+
+ * @param string String to check for spam
+ * @param string Author name
+ * @param string Author e-mail
+ * @param string Author website
+ * @param string Author IP
+ * @return bool
+ */
+
+function spamalyze($string, $name = false, $email = false, $url = false, $ip = false)
+{
+ global $db, $session, $paths, $template, $plugins; // Common objects
+ if ( !$ip )
+ $ip =& $_SERVER['REMOTE_ADDR'];
+
+ $code = $plugins->setHook('spam_check');
+ foreach ( $code as $cmd )
+ {
+ $result = eval($cmd);
+ if ( !$result )
+ return false;
+ }
+ return true;
+}
+
+/**
* Paginates (breaks into multiple pages) a MySQL result resource, which is treated as unbuffered.
* @param resource The MySQL result resource. This should preferably be an unbuffered query.
* @param string A template, with variables being named after the column name
diff -r 880c4b7eb658 -r 9d5c04c1414f includes/pageprocess.php
--- a/includes/pageprocess.php Sat Jan 17 15:16:36 2009 -0500
+++ b/includes/pageprocess.php Sun Jan 25 21:18:05 2009 -0500
@@ -198,6 +198,11 @@
return false;
}
}
+ if ( $this->revision_id > 0 && !$this->perms->get_permissions('history_view') )
+ {
+ $this->err_access_denied();
+ return false;
+ }
// Is there a custom function registered for handling this namespace?
// DEPRECATED (even though it only saw its way into one alpha release.)
@@ -443,6 +448,13 @@
}
}
+ // Spam check
+ if ( !spamalyze($text) )
+ {
+ $this->raise_error($lang->get('editor_err_spamcheck_failed'));
+ return false;
+ }
+
//
// Protection validated; update page content
//
diff -r 880c4b7eb658 -r 9d5c04c1414f includes/pageutils.php
--- a/includes/pageutils.php Sat Jan 17 15:16:36 2009 -0500
+++ b/includes/pageutils.php Sun Jan 25 21:18:05 2009 -0500
@@ -694,7 +694,7 @@
$i++;
$strings = Array();
$bool = Array();
- if ( $session->get_permissions('mod_comments') || $row['approved'] )
+ if ( $session->get_permissions('mod_comments') || $row['approved'] == COMMENT_APPROVED )
{
$list .= $i . ' : { \'comment\' : unescape(\''.rawurlencode($row['comment_data']).'\'), \'name\' : unescape(\''.rawurlencode($row['name']).'\'), \'subject\' : unescape(\''.rawurlencode($row['subject']).'\'), }, ';
diff -r 880c4b7eb658 -r 9d5c04c1414f includes/plugins.php
--- a/includes/plugins.php Sat Jan 17 15:16:36 2009 -0500
+++ b/includes/plugins.php Sun Jan 25 21:18:05 2009 -0500
@@ -121,8 +121,9 @@
* @param array Deprecated.
*/
- function setHook($name, $opts = Array()) {
- if(isset($this->hook_list[$name]) && is_array($this->hook_list[$name]))
+ function setHook($name, $opts = Array())
+ {
+ if ( !empty($this->hook_list[$name]) && is_array($this->hook_list[$name]) )
{
return array(implode("\n", $this->hook_list[$name]));
}
@@ -149,8 +150,9 @@
*/
- function attachHook($name, $code) {
- if(!isset($this->hook_list[$name]))
+ function attachHook($name, $code)
+ {
+ if ( !isset($this->hook_list[$name]) )
{
$this->hook_list[$name] = Array();
}
diff -r 880c4b7eb658 -r 9d5c04c1414f includes/template.php
--- a/includes/template.php Sat Jan 17 15:16:36 2009 -0500
+++ b/includes/template.php Sun Jan 25 21:18:05 2009 -0500
@@ -611,36 +611,30 @@
{
$db->_die();
}
- $nc = $db->numrows();
- $nu = 0;
- $na = 0;
+ $num_comments = $db->numrows();
+ $approval_counts = array(COMMENT_UNAPPROVED => 0, COMMENT_APPROVED => 0, COMMENT_SPAM => 0);
while ( $r = $db->fetchrow() )
{
- if ( !$r['approved'] )
- {
- $nu++;
- }
- else
- {
- $na++;
- }
+ $approval_counts[$r['approved']]++;
}
$db->free_result();
- $n = ( $session->check_acl_scope('mod_comments', $local_namespace) && $perms->get_permissions('mod_comments') ) ? (string)$nc : (string)$na;
- if ( $session->check_acl_scope('mod_comments', $local_namespace) && $perms->get_permissions('mod_comments') && $nu > 0 )
+ // $n = ( $session->check_acl_scope('mod_comments', $local_namespace) && $perms->get_permissions('mod_comments') ) ? (string)$num_comments : (string)$na;
+ if ( $session->check_acl_scope('mod_comments', $local_namespace) && $perms->get_permissions('mod_comments') && ( $approval_counts[COMMENT_UNAPPROVED] + $approval_counts[COMMENT_SPAM] ) > 0 )
{
$subst = array(
- 'num_comments' => $nc,
- 'num_unapp' => $nu
+ 'num_comments' => $num_comments,
+ 'num_app' => $approval_counts[COMMENT_APPROVED],
+ 'num_unapp' => $approval_counts[COMMENT_UNAPPROVED],
+ 'num_spam' => $approval_counts[COMMENT_SPAM]
);
$btn_text = $lang->get('onpage_btn_discussion_unapp', $subst);
}
else
{
$subst = array(
- 'num_comments' => $nc
+ 'num_comments' => $num_comments
);
$btn_text = $lang->get('onpage_btn_discussion', $subst);
}
diff -r 880c4b7eb658 -r 9d5c04c1414f language/english/admin.json
--- a/language/english/admin.json Sat Jan 17 15:16:36 2009 -0500
+++ b/language/english/admin.json Sun Jan 25 21:18:05 2009 -0500
@@ -279,6 +279,11 @@
field_comment_allow_guests_yes: 'Yes',
field_comment_allow_guests_captcha: 'Require visual confirmation',
field_comment_allow_guests_no: 'No (require login)',
+ field_comment_spam_policy: 'Spam policy:',
+ field_comment_spam_policy_hint: 'This requres a spam filtering plugin to be installed.',
+ field_comment_spam_policy_moderate: 'Moderate comments (default)',
+ field_comment_spam_policy_reject: 'Reject post',
+ field_comment_spam_policy_accept: 'Ignore and accept posts',
// Section: disable site
heading_disablesite: 'Disable all site access',
diff -r 880c4b7eb658 -r 9d5c04c1414f language/english/core.json
--- a/language/english/core.json Sat Jan 17 15:16:36 2009 -0500
+++ b/language/english/core.json Sun Jan 25 21:18:05 2009 -0500
@@ -211,12 +211,21 @@
msg_count_unapp_one: 'However, there is 1 additional comment awaiting approval.',
msg_count_unapp_plural: 'However, there are %num_unapp% additional comments awaiting approval.',
+ msg_foe_comment_hidden: 'Post from foe hidden.',
+ btn_display_foe_comment: 'Display post',
+
msg_note_unapp: '(Unapproved)',
+ msg_note_spam: '(Spam)',
msg_ip_address: 'IP address:',
msg_delete_confirm: 'Do you really want to delete this comment?',
+ err_captcha_wrong: 'The confirmation code you entered was incorrect.',
+ err_spamcheck_failed_rejected: 'Your comment was rejected because it appears to be spam.',
+ err_spamcheck_failed_flagged: 'Your comment was posted, but it appears to be spam and has been flagged as such for a moderator to review.',
+ ajax_err_generic_title: 'Error fetching comment data',
+
postform_title: 'Got something to say?',
postform_blurb: 'If you have comments or suggestions on this article, you can shout it out here.',
postform_blurb_unapp: 'Before your post will be visible to the public, a moderator will have to approve it.',
@@ -250,7 +259,7 @@
lbl_page_external: 'external page',
btn_discussion: 'discussion (%num_comments%)',
- btn_discussion_unapp: 'discussion (%num_comments% total, %num_unapp% unapp.)',
+ btn_discussion_unapp: 'discussion (%num_comments%) [!]',
btn_edit: 'edit this page',
btn_viewsource: 'view source',
btn_history: 'history',
@@ -332,6 +341,7 @@
err_no_permission: 'You do not have permission to edit this page.',
err_page_protected: 'This page is protected, and you do not have permission to edit protected pages.',
err_captcha_wrong: 'The confirmation code you entered is incorrect.',
+ err_spamcheck_failed: 'Your edit was rejected because it looks like spam.',
msg_editor_heading: 'Editing page',
msg_saved: 'Your changes to this page have been saved.',
diff -r 880c4b7eb658 -r 9d5c04c1414f plugins/SpecialAdmin.php
--- a/plugins/SpecialAdmin.php Sat Jan 17 15:16:36 2009 -0500
+++ b/plugins/SpecialAdmin.php Sun Jan 25 21:18:05 2009 -0500
@@ -304,6 +304,10 @@
if(isset($_POST['enable-comments'])) setConfig('enable_comments', '1');
else setConfig('enable_comments', '0');
setConfig('comments_need_login', $_POST['comments_need_login']);
+ if ( in_array($_POST['comment_spam_policy'], array('moderate', 'reject', 'accept')) )
+ {
+ setConfig('comment_spam_policy', $_POST['comment_spam_policy']);
+ }
// Powered by link
if ( isset($_POST['enano_powered_link']) ) setConfig('powered_btn', '1');
@@ -604,6 +608,27 @@
+
+