# 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 @@ + + + + get('acpgc_field_comment_spam_policy'); ?>
+ get('acpgc_field_comment_spam_policy_hint'); ?> + + + + + + +