Mollom on your wordpress blog
Author: Matthias Vandermaesen
Version: 0.7.5
Author URI: http://www.colada.be
Email: matthias@colada.be
Version history:
- 2 april 2008: creation
- 12 may 2008: first closed release
- 22 may 2008: second closed release
- 29 may 2008: third closed release
- 3 june 2008: first public release
- 28 juni 2008: second public release
- 1 juli 2008: small bugfix release
- 20 juli 2008: small bugfix release
- 24 augustus 2008: third public release
- 24 september 2008: small bugfix release
- 10 november 2008: small bugfix release
- 27 november 2008: fourth public release
- 27 december 2008: fifth public release
- 12 february 2009: sixth public release
- 16 march 2009: small bugfix release
- 18 april 2009: small additions release
- 20 december 2009: small bugfix release
*/
/* Copyright 2008, 2009 Matthias Vandermaesen (email : matthias@colada.be)
This program 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 2 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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
define( 'MOLLOM_API_VERSION', '1.0' );
define( 'MOLLOM_VERSION', '0.7.5' );
define( 'MOLLOM_USER_AGENT', '(Incutio XML-RPC) WP Mollom for Wordpress ' . MOLLOM_VERSION );
define( 'MOLLOM_TABLE', 'mollom' );
define( 'MOLLOM_I8N', 'wp-mollom' );
define( 'MOLLOM_ERROR' , 1000 );
define( 'MOLLOM_REFRESH' , 1100 );
define( 'MOLLOM_REDIRECT', 1200 );
define( 'MOLLOM_ANALYSIS_HAM' , 1);
define( 'MOLLOM_ANALYSIS_SPAM' , 2);
define( 'MOLLOM_ANALYSIS_UNSURE' , 3);
/**
* mollom_activate
* activate the plugin and install stuff upon first activation
*/
function mollom_activate() {
global $wpdb, $wp_db_version, $wp_roles;
// create a new table to store mollom sessions if it doesn't exist
$mollom_table = $wpdb->prefix . MOLLOM_TABLE;
if($wpdb->get_var("SHOW TABLES LIKE '$mollom_table'") != $mollom_table) {
$sql = "CREATE TABLE " . $mollom_table . " (
`comment_ID` BIGINT( 20 ) UNSIGNED NOT NULL DEFAULT '0',
`mollom_session_ID` VARCHAR( 40 ) NULL DEFAULT NULL,
`mollom_had_captcha` INT ( 1 ) NOT NULL DEFAULT '0',
`mollom_spaminess` FLOAT NOT NULL DEFAULT '0.00',
UNIQUE (
`comment_ID` ,
`mollom_session_ID`
)
);";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
// if there is no version option, mollom is installed for the first time
if (!get_option('mollom_version')) {
//Set these variables if they don't exist
$version = MOLLOM_VERSION;
add_option('mollom_version', $version);
}
// also, let's create these variables if they don't exist
if(!get_option('mollom_private_key'))
add_option('mollom_private_key', '');
if(!get_option('mollom_public_key'))
add_option('mollom_public_key', '');
if(!get_option('mollom_servers'))
add_option('mollom_servers', NULL);
if(!get_option('mollom_ham_count'))
add_option('mollom_ham_count', 0);
if(!get_option('mollom_spam_count'))
add_option('mollom_spam_count', 0);
if(!get_option('mollom_unsure_count'))
add_option('mollom_unsure_count', 0);
if(!get_option('mollom_count_moderated'))
add_option('mollom_count_moderated', 0);
if(!get_option('mollom_site_policy'))
add_option('mollom_site_policy', true);
// deprecated. Backward compatibility only
if((!get_option('mollom_dbrestore')) && ($wp_db_version < 8645))
add_option('mollom_dbrestore', false);
if(!get_option('mollom_reverseproxy'))
add_option('mollom_reverseproxy', false);
if(!get_option('mollom_reverseproxy_addresses'))
add_option('mollom_reverseproxy_addresses', NULL);
if(!get_option('mollom_roles')) {
$mollom_roles = array();
foreach ($wp_roles->roles as $role => $data) {
$mollom_roles[] = $role;
}
add_option('mollom_roles', serialize($mollom_roles));
}
// if a previous installed version doesn't match with this version, mollom might need an update
if (get_option('mollom_version') != MOLLOM_VERSION) {
// updates of the database if the plugin was already installed
$version = MOLLOM_VERSION;
update_option('mollom_version', $version);
// legacy code here:
// 1. moving data from old to new data model if necessary (0.4 -> 0.5)
$comments_table = $wpdb->prefix . 'comments';
// only update if mollom_session_id still exists
foreach ($wpdb->get_col("DESC $comments_table", 0) as $column ) {
if ($column == 'mollom_session_ID') {
$comments = $wpdb->get_results("SELECT comment_ID, mollom_session_ID FROM $comments_table WHERE mollom_session_ID IS NOT NULL");
if ($comments) {
$stat = true;
foreach($comments as $comment) {
if(!$wpdb->query( $wpdb->prepare("INSERT INTO $mollom_table(comment_ID, mollom_session_ID) VALUES(%d, %s)", $comment->comment_ID, $comment->mollom_session_ID))) {
$stat = false;
}
}
if($stat) {
$wpdb->query("ALTER TABLE $wpdb->comments DROP COLUMN mollom_session_id");
} else {
wp_die(__('Something went wrong while moving data from comments to the Mollom data table', MOLLOM_I8N));
}
}
}
}
// 2. Add extra columns to the mollom table if it already exists
$columns = $wpdb->get_col("DESC $mollom_table", 0);
if (!in_array('mollom_had_captcha', $columns)) {
$wpdb->query("ALTER TABLE $mollom_table ADD mollom_had_captcha TINYINT (1) NOT NULL DEFAULT 0");
}
if (!in_array('mollom_spaminess', $columns)) {
$wpdb->query("ALTER TABLE $mollom_table ADD mollom_spaminess FLOAT NOT NULL DEFAULT '0.00'");
}
// end of legacy code
}
}
register_activation_hook(__FILE__, 'mollom_activate');
/**
* mollom_deactivate
* restore database to previous state upon deactivation
*/
function mollom_deactivate() {
global $wpdb, $wp_db_version;
// only delete if full restore is allowed
// Deprecated for WP 2.7 and above
if ((get_option('mollom_dbrestore')) && (8645 > $wp_db_version)) {
delete_option('mollom_private_key');
delete_option('mollom_public_key');
delete_option('mollom_servers');
delete_option('mollom_version');
delete_option('mollom_count');
delete_option('mollom_ham_count');
delete_option('mollom_spam_count');
delete_option('mollom_unsure_count');
delete_option('mollom_count_moderated');
delete_option('mollom_reverseproxy');
delete_option('mollom_site_policy');
delete_option('mollom_reverseproxy_addresses');
$mollom_table = $wpdb->prefix . MOLLOM_TABLE;
// delete MOLLOM_TABLE
$wpdb->query("DROP TABLE $mollom_table");
delete_option('mollom_dbrestore');
}
}
register_deactivation_hook(__FILE__, 'mollom_deactivate');
/**
* mollom_init
* This function runs all logic needed on the init hook
*/
function mollom_init() {
// load the text domain for localization
load_plugin_textdomain(MOLLOM_I8N, false, dirname(plugin_basename(__FILE__)));
}
add_action('init', 'mollom_init');
/**
* mollom_config_page
* hook the config page in the Wordpress administration module
*/
function mollom_config_page() {
global $submenu;
if ((function_exists('add_submenu_page')) && (isset($submenu['options-general.php']))) {
add_submenu_page('options-general.php', __('Mollom', MOLLOM_I8N), __('Mollom', MOLLOM_I8N), 'manage_options', 'mollom-key-config', 'mollom_config');
}
}
add_action('admin_menu','mollom_config_page');
/**
* mollom_admin_pages
* hook the manage page in the Wordpress administration module
*/
function mollom_admin_pages() {
if (function_exists('add_comments_page')) {
add_comments_page(__('Mollom', MOLLOM_I8N), __('Mollom', MOLLOM_I8N), 'moderate_comments', 'mollommanage', 'mollom_manage');
add_comments_page(__('Mollom statistics', 'wp-mollom'), __('Mollom statistics', 'wp-mollom'), 'manage_options', 'mollomstats', 'mollom_statistics');
} else {
// Deprecated. Backward compatibility.
global $submenu;
if ( isset( $submenu['edit-comments.php'] ) ) {
add_submenu_page('edit-comments.php', __('Mollom', MOLLOM_I8N), __('Mollom', MOLLOM_I8N), 'moderate_comments', 'mollommanage', 'mollom_manage');
add_submenu_page('edit-comments.php', __('Mollom statistics', 'wp-mollom'), __('Mollom statistics', 'wp-mollom'), 'manage_options', 'mollomstats', 'mollom_statistics');
}
}
}
add_action('admin_menu','mollom_admin_pages');
/**
* _mollom_set_plugincount
* Sets the count of comments asserted as spam or unsure. Local stored data is used to generate statistics
* @param boolean $action The action which was taken and for wich to set the count.
*/
function _mollom_set_plugincount($action) {
switch ($action) {
default:
case "spam":
$count = get_option('mollom_spam_count');
$count++;
update_option('mollom_spam_count', $count);
break;
case "ham":
$count = get_option('mollom_ham_count');
$count++;
update_option('mollom_ham_count', $count);
break;
case "unsure":
// make a spam count into an unsure count if a captcha was correctly completed!
$count = get_option('mollom_spam_count');
$count--;
update_option('mollom_spam_count', $count);
$count = get_option('mollom_unsure_count');
$count++;
update_option('mollom_unsure_count', $count);
break;
case "moderated":
$count_moderated = get_option('mollom_count_moderated');
$count_moderated++;
update_option('mollom_count_moderated', $count_moderated);
break;
}
}
/**
* show_statistics
* Shows statistics from the Mollom servers in the Wordpress administration module (hooks on plugins.php)
*/
function mollom_statistics() {
?>
get_error_code()) == MOLLOM_ERROR) {
$ms[] = 'mollomerror';
// reset the wordpress variables to whatever (empty or
// previous value) is in the buffer if mollom returned error code 1000
update_option('mollom_private_key', $tmp_privatekey);
update_option('mollom_public_key', $tmp_publickey);
}
if (($result->get_error_code()) != MOLLOM_ERROR) {
$ms[] = 'networkerror';
}
$errormsg = $result->get_error_message();
}
if (is_bool($result)) {
$ms[] = 'correctkey';
}
$messages = array(
'privatekeyempty' => array('color' => 'aa0', 'text' => __('Your private key is empty.', MOLLOM_I8N)),
'publickeyempty' => array('color' => 'aa0', 'text' => __('Your public key is empty.', MOLLOM_I8N)),
'wrongkey' => array('color' => 'd22', 'text' => __('The key you provided is wrong.', MOLLOM_I8N)),
'mollomerror' => array('color' => 'd22', 'text' => sprintf(__('Mollom error: %s', MOLLOM_I8N), $errormsg)),
'networkerror' => array('color' =>'d22', 'text' => sprintf(__('Network error: %s', MOLLOM_I8N), $errormsg)),
'correctkey' => array('color' => '2d2', 'text' => __('Your keys are valid.', MOLLOM_I8N))
);
?>
prefix . MOLLOM_TABLE;
$ms = array();
$mollom_sessionid = $wpdb->get_var( $wpdb->prepare("SELECT mollom_session_ID FROM $mollom_table WHERE comment_ID = %d", $comment_ID) );
switch($action) {
case $action == "spam":
case $action == "profanity":
case $action == "unwanted":
case $action == "low-quality":
$data = array('feedback' => $action, 'session_id' => $mollom_sessionid);
$result = mollom('mollom.sendFeedback', $data);
if($result) {
if($wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->comments, $mollom_table USING $wpdb->comments INNER JOIN $mollom_table USING(comment_ID) WHERE $wpdb->comments.comment_ID = %d", $comment_ID))) {
// update the statistics for manual moderation
_mollom_set_plugincount("moderated");
$ms[] = 'allsuccess'; // return all success on successfull feedback
} else {
$ms[] = 'feedbacksuccess';
}
}
else if (function_exists( 'is_wp_error' ) && is_wp_error( $result )) {
$ms[] = 'mollomerror';
}
else {
$ms[] = 'networkfail';
}
break;
case $action == "approve":
if (wp_set_comment_status($comment_ID, 'approve')) {
$ms[] = 'approved';
} else {
$ms[] = 'approvefail';
}
break;
case $action == "unapprove":
if (wp_set_comment_status($comment_ID, 'hold')) {
$ms[] = 'unapproved';
} else {
$ms[] = 'approvefail';
}
break;
default:
$ms[] = 'invalidaction';
return $ms;
break;
}
return $ms; // return the result
}
/**
* mollom_manage
* Moderate messages that have a stored Mollom session ID
*/
function mollom_manage() {
if (function_exists('current_user_can') && !current_user_can('manage_options')) {
die(__('Cheatin’ uh?', MOLLOM_I8N));
}
global $wpdb;
$feedback = array();
$broken_comment = "";
// moderation of a single item
if ($_GET['maction'] && !$_POST['mollom-delete-comments']) {
if (function_exists('check_admin_referer')) {
check_admin_referer('mollom-moderate-comment');
}
$mollom_private_key = get_option('mollom_private_key');
$mollom_public_key = get_option('mollom_public_key');
$comment_ID = $_GET['c'];
if (empty($mollom_private_key) || empty($mollom_public_key)) {
$feedback[$comment_ID] = array('emptykeys');
} else {
$action = $_GET['maction'];
$feedback[$comment_ID] = _mollom_send_feedback($action, $comment_ID);
}
}
// moderation of multiple items (bulk)
if ($_POST['mollom-delete-comments']) {
if (function_exists('check_admin_referer')) {
check_admin_referer('mollom-bulk-moderation');
}
$mollom_private_key = get_option('mollom_private_key');
$mollom_public_key = get_option('mollom_public_key');
if (empty($mollom_private_key) || empty($mollom_public_key)) {
$feedback[] = array('emptykeys');
} else {
$multiple_failed = false;
foreach($_POST["mollom-delete-comments"] as $comment_ID) {
$result = _mollom_send_feedback($action, $comment_ID);
switch ($result[0]) {
case 'allsuccess':
case 'unapprove':
case 'approve':
$multipe_failed = true;
break;
default:
$multiple_failed = false;
}
$feedback[$comment_ID] = $result;
}
}
}
// Generate local statistics
$count_nominal = _mollom_calc_statistics('nominal');
$count_percentage = _mollom_calc_statistics('percentage');
// from here on: generate messages and overview page
$messages = array('allsuccess' => array('color' => 'd2f2d7', 'text' => __('Feedback sent to Mollom. The comment was successfully deleted.', MOLLOM_I8N)),
'approved' => array('color' => 'd2f2d7', 'text' => __('You flagged this comment as approved.', MOLLOM_I8N)),
'unapproved' => array('color' => 'd2f2d7', 'text' => __('You flagged this comment as unapproved.', MOLLOM_I8N)),
'feedbacksuccess' => array('color' => 'f6d5cb', 'text' => __('Feedback sent to Mollom but the comment could not be deleted.', MOLLOM_I8N)),
'networkfail' => array('color' => 'f6d5cb', 'text' => __('Mollom was unreachable. Maybe the service is down or there is a network disruption.', MOLLOM_I8N)),
'emptykeys' => array('color' => 'f6d5cb', 'text' => __('Could not perform action because the Mollom plugin is not configured. Please configure the settings first.', MOLLOM_I8N)),
'mollomerror' => array('color' => 'f6d5cb', 'text' => __('Mollom could not process your request.', MOLLOM_I8N)),
'approvefail' => array('color' => 'f6d5cb', 'text' => __('Wordpress could not (un)approve this comment.', MOLLOM_I8N)),
'invalidaction' => array('color' => 'f6d5cb', 'text' => __('Invalid Mollom feedback action.', MOLLOM_I8N)));
// pagination code
$show_next = true;
$mollom_table = $wpdb->prefix . MOLLOM_TABLE;
$count = $wpdb->get_var("SELECT COUNT(comments.comment_ID) FROM $wpdb->comments comments, $mollom_table mollom WHERE mollom.comment_ID = comments.comment_ID");
if ($count > 0) {
$apage = (($_GET['apage']) ? $_GET['apage'] : 1);
$pagination = _mollom_manage_paginate($apage, $count);
$limit = 15;
$start = (($apage < 2) ? 0 : (($apage - 1) * 15));
$wpdb->show_errors();
$comments = $wpdb->get_results( $wpdb->prepare("SELECT comments.comment_ID, mollom.mollom_had_captcha, mollom.mollom_spaminess FROM $wpdb->comments comments, $mollom_table mollom WHERE mollom.comment_ID = comments.comment_ID ORDER BY comment_date DESC LIMIT %d, %d", $start, $limit) );
} else {
$comments = false;
}
?>
some statistics.', MOLLOM_I8N); ?>
Click to display a detailed report.', MOLLOM_I8N); ?>
Click to display a detailed report.', MOLLOM_I8N); ?>
$comment ) :
foreach( $comment as $message) :
?>
0) {
$total_pages += 1;
}
// calculate pagination context
$buffer = 1;
for ($i = 1; $i <= $total_pages; $i++) {
// break if the last page is reached
if ($current_page == $total_pages) {
if ($total_pages > 1) {
$start_offset = $total_pages - 1;
} else {
$start_offset = 1;
}
break;
}
// calculate offset depending on which page we are
if ((($i % 2) == 0)) {
if ($i > $current_page) {
$start_offset = $buffer;
break;
} elseif ($i == $current_page) {
$start_offset = $buffer + 1;
break;
} else {
$buffer = $i;
}
}
}
// previous/next buttons
$prev_page = false;
if ($current_page > 1) {
$prev_page = $current_page - 1;
}
$next_page = false;
if ($current_page < $total_pages) {
$next_page = $current_page + 1;
}
$pages = '';
// start generating links and such
if ($prev_page) {
$pages = "" . __('«', MOLLOM_I8N) . "";
}
$context = 3;
$context = (($context < $total_pages) ? $context : ($total_pages + 1));
for ($i = 0; $i < $context; $i++) {
$page = $start_offset + $i;
if (($page * $per_page) <= $count) {
if($page != $current_page) {
$pages .= " " . $page . "";
} else {
$pages .= " " . $page . " ";
}
}
}
//we're approaching the last page now
if ($start_offset < ($total_pages - 2)) {
if ($start_offset < ($total_pages - $context)) {
$pages .= " ... ";
}
$pages .= "" . $total_pages . "";
}
if ($next_page) {
$pages .= " " . __('»', MOLLOM_I8N) . "";
}
return $pages;
}
/**
* mollom_manage_wp_queue
* passes messages as spam to Mollom when moderated through the default WP 'comments' panel
* @param integer $comment_ID the id of the comment that is being moderated
* @param string $comment_status the status that was passed by the user through the default comments panel
* @return integer The id of the coment is passed back to the main program flow
*/
function mollom_manage_wp_queue($comment_ID) {
$comment = get_commentdata($comment_ID, 1, true);
$post_id = $comment['comment_post_ID'];
if ($comment['comment_approved'] == 'spam') {
_mollom_send_feedback('spam', $comment_ID);
}
return $post_id;
}
add_action('wp_set_comment_status', 'mollom_manage_wp_queue');
/**
* mollom_moderate_comment
* Show moderation options in your theme if you're logged in and have permissions. Must be within the comment loop.
* @param string The moderation links to show as a string
*/
function mollom_moderate_comment($comment_ID) {
if (function_exists('current_user_can') && current_user_can('manage_options')) {
$spam = clean_url(wp_nonce_url('edit-comments.php?page=mollommanage&c=' . $comment_ID . '&maction=spam', 'mollom-moderate-comment'));
$profanity = clean_url(wp_nonce_url('edit-comments.php?page=mollommanage&c=' . $ccomment_ID . '&maction=profanity', 'mollom-moderate-comment'));
$lowquality = clean_url(wp_nonce_url('edit-comments.php?page=mollommanage&c=' . $comment_ID . '&maction=low-quality', 'mollom-moderate-comment'));
$unwanted = clean_url(wp_nonce_url('edit-comments.php?page=mollommanage&c=' . $comment_ID . '&maction=unwanted', 'mollom-moderate-comment'));
$approved = clean_url(wp_nonce_url('edit-comments.php?page=mollommanage&c=' . $comment_ID . '&maction=approve', 'mollom-moderate-comment'));
$unapproved = clean_url(wp_nonce_url('edit-comments.php?page=mollommanage&c=' . $comment_ID . '&maction=unapprove', 'mollom-moderate-comment'));
$str = 'Moderate: ' . _e('spam', MOLLOM_I8N) . ' | ' .
'' . _e('profanity', MOLLOM_I8N) . ' | ' .
'' . _e('low quality', MOLLOM_I8N) . ' | ' .
'' . _e('unwanted', MOLLOM_I8N) . ' | ' .
'' . _e('approved', MOLLOM_I8N) . ' | ' .
'' . _e('unapproved', MOLLOM_I8N) . '';
return $str;
}
}
/**
* mollom_check_comment
* Check if a comment is spam or ham
* @param array $comment the comment passed by the preprocess_comment hook
* @return array The comment passed by the preprocess_comment hook
*/
function mollom_check_comment($comment) {
global $mollom_sessionid;
// if it's a trackback, pass it on
if($comment['comment_type'] == 'trackback') {
mollom_check_trackback($comment);
}
$private_key = get_option('mollom_private_key');
$public_key = get_option('mollom_public_key');
// check if the client is configured all toghether
if ((empty($private_key)) || (empty($public_key))) {
if (get_option('mollom_site_policy')) {
wp_die(__('You haven\'t configured Mollom yet! Per the website\'s policy. We could not process your comment.', MOLLOM_I8N));
}
}
// only check the captcha if there is an active Mollom session
// skip to the captcha check if session ID was $_POST'ed
if ($_POST['mollom_sessionid']) {
$comment = mollom_check_captcha($comment);
return $comment;
} else {
// If a logged in user exists check if the role is exempt from a Mollom check
// non-registered visitors don't have a role so their submissions are always checked
$user = wp_get_current_user();
if ($user->ID) {
$mollom_roles = unserialize(get_option('mollom_roles'));
$detected = array_intersect($user->roles, $mollom_roles);
if (count($detected) > 0) {
return $comment;
}
}
$mollom_comment_data = array('post_body' => $comment['comment_content'],
'author_name' => $comment['comment_author'],
'author_url' => $comment['comment_author_url'],
'author_mail' => $comment['comment_author_email'],
'author_ip' => _mollom_author_ip());
$result = mollom('mollom.checkContent', $mollom_comment_data);
// quit if an error was thrown else return to WP Comment flow
if (function_exists('is_wp_error') && is_wp_error($result)) {
if(get_option('mollom_site_policy')) {
wp_die($result, __('Something went wrong...', MOLLOM_I8N));
} else {
return $comment;
}
}
$mollom_sessionid = $result['session_id'];
switch($result['spam']) {
case MOLLOM_ANALYSIS_HAM: {
// let the comment pass
global $spaminess;
$spaminess = $result['quality'];
_mollom_set_plugincount("ham");
add_action('comment_post', '_mollom_save_session', 1);
return $comment;
}
case MOLLOM_ANALYSIS_UNSURE: {
// show a CAPTCHA and and set the count of blocked messages
_mollom_set_plugincount("spam");
$mollom_comment = _mollom_set_fields($_POST, $comment);
$mollom_comment['mollom_sessionid'] = $result['session_id'];
$mollom_comment['mollom_spaminess'] = $result['quality'];
mollom_show_captcha('', $mollom_comment);
die();
}
case MOLLOM_ANALYSIS_SPAM: {
// kill the process here because of spam detection and set the count of blocked messages
_mollom_set_plugincount("spam");
wp_die(__('Your comment has been marked as spam or unwanted by Mollom. It could not be accepted.', MOLLOM_I8N));
}
default: {
// default behaviour: trigger an error (policy mode)
if (function_exists('is_wp_error') && is_wp_error($result)) {
if(get_option('mollom_site_policy')) {
wp_die($result, __('Something went wrong...', MOLLOM_I8N));
} else {
return $comment;
}
}
}
}
}
// last resort: die to protect the db
wp_die(-6, __('Something went wrong...', MOLLOM_I8N));
}
add_action('preprocess_comment', 'mollom_check_comment');
/**
* mollom_check_trackback
* check if a trackback is ham or spam
* @param array $comment the comment passed by the mollom_check_comment function
* @return array The comment passed by the preprocess_comment hook
*/
function mollom_check_trackback($comment) {
global $mollom_sessionid;
$private_key = get_option('mollom_private_key');
$public_key = get_option('mollom_public_key');
// check if the client is configured
if ((empty($private_key)) || (empty($public_key))) {
if (get_option('mollom_site_policy')) {
wp_die(__('You haven\'t configured Mollom yet! Per the website\'s policy. We could not process your comment.', MOLLOM_I8N));
}
}
$mollom_comment_data = array('post_body' => $comment['comment_content'],
'author_name' => $comment['comment_author'],
'author_url' => $comment['comment_author_url'],
'author_mail' => $comment['comment_author_email'],
'author_ip' => _mollom_author_ip());
$result = mollom('mollom.checkContent', $mollom_comment_data);
// quit if an error was thrown else return to WP Comment flow
if (function_exists('is_wp_error') && is_wp_error($result)) {
if(get_option('mollom_site_policy')) {
wp_die($result, __('Something went wrong...', MOLLOM_I8N));
} else {
return $comment;
}
}
$mollom_sessionid = $result['session_id'];
switch($result['spam']) {
case MOLLOM_ANALYSIS_HAM: {
// let the comment pass
global $spaminess;
$spaminess = $result['quality'];
_mollom_set_plugincount("ham");
add_action('comment_post', '_mollom_save_session', 1); // save session!!
return $comment;
}
case MOLLOM_ANALYSIS_SPAM:
case MOLLOM_ANALYSIS_UNSURE: {
// kill the process here because of unsure/spam detection
// Trackbacks don't get a CAPTCHA
_mollom_set_plugincount("spam");
die();
}
default: {
if (function_exists('is_wp_error') && is_wp_error($result)) {
if(get_option('mollom_site_policy')) {
die();
} else {
return $comment;
}
}
}
}
// last resort: die to protect the db
wp_die(-6, __('Something went wrong...', MOLLOM_I8N));
}
/**
* mollom_check_captcha
* Check the answer of the CAPTCHA presented by Mollom. Called through the pre_process_hook as a callback.
* @param array $comment the comment array passed by the pre_process hook
* @return array The comment array passed by the pre_process hook
*/
function mollom_check_captcha($comment) {
global $wpdb;
$result = false;
// strip redundant slashes
$comment['comment_content'] = stripslashes($comment['comment_content']);
$mollom_session_id = $_POST['mollom_sessionid'];
$solution = $_POST['mollom_solution'];
$mollom_image_session = $_POST['mollom_image_session'];
$mollom_audio_session = $_POST['mollom_audio_session'];
if (empty($mollom_session_id)) {
$message = __('The Mollom session ID part (a hidden field) is missing from the form you tried to submit.', MOLLOM_I8N);
$mollom_comment = _mollom_set_fields($_POST, $comment);
mollom_show_captcha($message, $mollom_comment);
die();
}
if (empty($solution)) {
$message = __('You didn\'t fill out all the required fields, please try again', MOLLOM_I8N);
$mollom_comment = _mollom_set_fields($_POST, $comment);
mollom_show_captcha($message, $mollom_comment);
die();
}
// check captcha sessions and solution. If the image gives false, then try the audio session.
// Normally the mollom session id, the image session id and the audio session id are the same though no guarantees can be made
$data = array('session_id' => $mollom_image_session, 'solution' => $solution);
if (!($result = mollom('mollom.checkCaptcha', $data))) {
$data = array('session_id' => $mollom_audio_session, 'solution' => $solution);
$result = mollom('mollom.checkCaptcha', $data);
}
// quit if an error was thrown else return to WP Comment flow
if (function_exists('is_wp_error') && is_wp_error($result)) {
if(get_option('mollom_site_policy')) {
wp_die($result, __('Something went wrong...', MOLLOM_I8N));
} else {
return $comment;
}
}
// if correct
else if ($result) {
global $mollom_sessionid, $spaminess;
$mollom_sessionid = $_POST['mollom_sessionid'];
$spaminess = $_POST['mollom_spaminess'];
$comment['comment_content'] = htmlspecialchars_decode($comment['comment_content']);
add_action('comment_post', '_mollom_save_session', 1);
add_action('comment_post', '_mollom_save_had_captcha', 1);
_mollom_set_plugincount("unsure");
return $comment;
}
// if incorrect
else if (!$result) {
// let's be forgiving and provide with a new CAPTCHA
$message = __('The solution you submitted to the CAPTCHA was incorrect. Please try again...', MOLLOM_I8N);
$mollom_comment = _mollom_set_fields($_POST, $comment);
mollom_show_captcha($message, $mollom_comment);
die();
}
// last resort: die to protect the db
wp_die(-6, __('Something went wrong...', MOLLOM_I8N));
}
/**
* _mollom_set_fields
* This is a helper function. Get all the applicable comment fields from $_POST and $comment and put them in one array before passing on to show_captcha()
* @param array $post the $_POST array
* @param array $comment the $comment array which is passed through the add_action hook
*/
function _mollom_set_fields($post = array(), $comment = array()) {
$mollom_comment = array('comment_post_ID' => $comment['comment_post_ID'],
'author' => $comment['comment_author'],
'url' => $comment['comment_author_url'],
'email' => $comment['comment_author_email'],
'comment' => $comment['comment_content'],
'comment_parent' => $comment['comment_parent']
);
// add possible extra fields to the $mollom_comment array
foreach ($post as $key => $value) {
if ((!array_key_exists($key, array_keys($mollom_comment))) && ($key != 'submit') && ($key != 'mollom_solution')) {
$mollom_comment[$key] = $value;
}
}
return $mollom_comment;
}
/**
* _mollom_get_fields
* This is a helper function. Generate HTML hidden fields from an array and display them in the CAPTCHA form. All fields except email/url are sanitized against non-western encoding sets.
* @param array $comment an array with fields where key is the name of the field and value is the value of the field
*/
function _mollom_get_fields($comment = array()) {
foreach ($comment as $key => $value) {
// sanitize for non-western encoding sets. Only URL and e-mail adress are exempted. Extra non-wp fields are included.
switch ($key) {
case 'url':
case 'email':
break;
default: {
$charset = get_option('blog_charset');
$value = htmlspecialchars(stripslashes($value), ENT_COMPAT, $charset);
break;
}
}
// output to a hidden field
?> _mollom_author_ip(), 'session_id' => $mollom_comment['mollom_sessionid']);
$result = mollom('mollom.getAudioCaptcha', $data);
if (function_exists('is_wp_error') && is_wp_error($result)) {
if(get_option('mollom_site_policy')) {
wp_die($result, __('Something went wrong...', MOLLOM_I8N));
}
}
$mollom_comment['mollom_audio_session'] = $result['session_id'];
$mollom_audio_captcha = $result['url'];
$result = mollom('mollom.getImageCaptcha', $data);
if (function_exists('is_wp_error') && is_wp_error($result)) {
if(get_option('mollom_site_policy')) {
wp_die($result, __('Something went wrong...', MOLLOM_I8N));
}
}
$mollom_comment['mollom_image_session'] = $result['session_id'];
$mollom_image_captcha = $result['url'];
?>
>
Mollom against spam. Mollom is unsure whether your comment was spam or not. Please complete this form by typing the text in the image in the input box. Additionally, you can also listen to a spoken version of the text.', MOLLOM_I8N); ?>
Mollom, download and install the plugin!', MOLLOM_I8N); ?>
prefix . MOLLOM_TABLE;
$result = $wpdb->query( $wpdb->prepare("INSERT INTO $mollom_table (comment_ID, mollom_session_ID, mollom_spaminess) VALUES(%d, %s, %s)", $comment_ID, $mollom_sessionid, $spaminess) );
return $comment_ID;
}
/**
* _mollom_had_captcha
* save wether or not a CAPTCHA was shown for this comment
* @param integer $comment_ID the id of the comment
* @return integer The id of the comment
*/
function _mollom_save_had_captcha($comment_ID) {
global $wpdb, $mollom_sessionid;
$mollom_table = $wpdb->prefix . MOLLOM_TABLE;
$result = $wpdb->query( $wpdb->prepare("UPDATE $mollom_table SET mollom_had_captcha = 1 WHERE comment_ID = %d", $comment_ID));
return $comment_ID;
}
/**
* mollom
* call to mollom API over XML-RPC.
* @param string $method the API function you like to call
* @param array $data the arguments the called API function you want to pass
* @return mixed Either a WP_Error on error or a mixed return depending on the called API function
*/
function mollom($method, $data = array()) {
// Location of the Incutio XML-RPC library which is integrated with Wordpress
// lazy loading: only if this function gets called
require_once(ABSPATH . '/wp-includes/class-IXR.php');
// let's set the user agent string
$user_agent = MOLLOM_USER_AGENT;
// let's fetch us some servers
if (get_option('mollom_servers') == NULL) {
$result = _mollom_retrieve_server_list();
if (function_exists('is_wp_error') && is_wp_error($result)) {
return $result;
}
}
$servers = explode('#', get_option('mollom_servers'));
// fail-over/loadbalancing act
foreach ($servers as $server) {
$mollom_client = new IXR_Client($server . '/' . MOLLOM_API_VERSION);
$mollom_client->useragent = $user_agent;
$result = $mollom_client->query($method, $data + _mollom_authenticate());
if($mollom_client->getErrorCode()) {
// refresh the server list and try again
if ($mollom_client->getErrorCode() == MOLLOM_REFRESH) {
$result = _mollom_retrieve_server_list();
if (function_exists('is_wp_error') && is_wp_error($result)) {
return $result;
} else {
$servers = explode('#', get_option('mollom_servers'));
}
}
// redirect to a different server
else if ($mollom_client->getErrorCode() == MOLLOM_REDIRECT) {
// $server is overloaded, let's try the next one
// do nothing, travel through the loop again and try the next server in the list
}
// Mollom triggered an error
else if ($mollom_client->getErrorCode() == MOLLOM_ERROR) {
// Something went wrong! Return the errorcode
$mollom_error = new WP_Error();
$mollom_error->add($mollom_client->getErrorCode(), $mollom_client->getErrorMessage());
return $mollom_error;
}
} else {
// return a response if all went well
return $mollom_client->getResponse();
}
}
// renew the server cache. Maybe this will fix things next time.
$result = _mollom_retrieve_server_list();
if (function_exists('is_wp_error') && is_wp_error($result)) {
return $result;
}
$mollom_error = new WP_Error();
$mollom_error->add(-6, __('The Mollom servers could not be contacted at this time. Please try again at a later time.', MOLLOM_I8N));
return $mollom_error;
}
/**
* _mollom_retrieve_server_list
* retrieves a list of servers and caches it in the database
* @return boolean true if a list was succesfully retrieved and stored. Otherwise, Mollom breaks here.
**/
function _mollom_retrieve_server_list() {
// hard coded list cfr API documentation, section 9
$servers = array(
'http://xmlrpc1.mollom.com/',
'http://xmlrpc2.mollom.com/',
'http://xmlrpc3.mollom.com/'
);
$user_agent = MOLLOM_USER_AGENT;
foreach($servers as $server) {
$mollom_client = new IXR_Client($server . MOLLOM_API_VERSION);
$mollom_client->useragent = $user_agent;
if(!$mollom_client->query('mollom.getServerList', _mollom_authenticate())) {
// Something went wrong! Let's try the next one in the list
} else {
$servers = $mollom_client->getResponse();
update_option('mollom_servers', implode('#', $servers));
return true;
}
}
$mollom_error = new WP_Error();
$mollom_error->add($mollom_client->getErrorCode(), $mollom_client->getErrorMessage());
return $mollom_error;
}
/**
* _mollom_nonce;
* generate a random nonce
* @return string A random generated nonce of 32 characters
*/
function _mollom_nonce() {
$str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
srand((double)microtime()*100000);
for($i = 0; $i < 32; $i++) {
$num = rand() % strlen($str);
$tmp = substr($strn, $num, 1);
$nonce .= $tmp;
}
return $nonce;
}
/**
* _mollom_authenticate
* set an array with all the neccessary data to authenticate to Mollom
* @return string $data the BASE64 encoded authentication string need by the mollom function.
*/
function _mollom_authenticate() {
$public_key = get_option('mollom_public_key');
$private_key = get_option('mollom_private_key');
// Generate a timestamp according to the dateTime format (http://www.w3.org/TR/xmlschema-2/#dateTime):
$time = gmdate("Y-m-d\TH:i:s.\\0\\0\\0O", time());
// generate a random nonce
$nonce = _mollom_nonce();
// Calculate a HMAC-SHA1 according to RFC2104 (http://www.ietf.org/rfc/rfc2104.txt):
$hash = base64_encode(
pack("H*", sha1((str_pad($private_key, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
pack("H*", sha1((str_pad($private_key, 64, chr(0x00)) ^ (str_repeat(chr(0x36), 64))) .
$time . ':' . $nonce . ':' . $private_key))))
);
// Store everything in an array. Elsewhere in the code, we'll add the
// acutal data before we pass it onto the XML-RPC library:
$data['public_key'] = $public_key;
$data['time'] = $time;
$data['hash'] = $hash;
$data['nonce'] = $nonce;
return $data;
}
/**
* _mollom_author_ip
* fetch user IP
* @return string The IP of the host from which the request originates
*/
function _mollom_author_ip() {
$ip_address = $_SERVER['REMOTE_ADDR'];
if(get_option('mollom_reverseproxy')) {
if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
$reverse_proxy_addresses = explode(get_option('mollom_reverseproxy_addresses'), ',');
if(!empty($reverse_proxy_addressses) && in_array($ip_address, $reverse_proxy_addresses, TRUE)) {
// If there are several arguments, we need to check the most
// recently added one, ie the last one.
$ip_address = array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
}
}
}
// If WP is run in a clustered environment
if (array_key_exists('HTTP_X_CLUSTER_CLIENT_IP', $_SERVER)) {
$ip_address = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
}
return $ip_address;
}