<?php
/*
Plugin Name: WordPress Hashcash
Plugin URI: http://dev.wp-plugins.org/wiki/wp-hashcash
Description: Comment submitters compute a special code using javascript before their comment is submitted. Very effective at blocking spambots and not noticable for commenters. XHTML 1.1 compliant.
Author: Matt Mullenweg, Elliott Back
Author URI: http://photomatt.net/, http://elliottback.com
Version: 1.6
Hat tips:	C.S. - http://www.cimmanon.org/
		Gene Shepherd - http://www.imporium.org/
		John F. - http://www.stonegauge.com/
		Magenson - http://blog.magenson.de/
		Matt Mullenweg - http://photomatt.net/
		Matt Warden - http://www.mattwarden.com/
		Paul Andrew Johnston - http://pajhome.org.uk/crypt/md5/
*/ 

define('HASHCASH_DEBUG', false);
define('HASHCASH_LOG_SIZE', 64000);

/* Generate a random string of length l */
function hashcash_random_string($l) {
	srand((double) microtime() * 1000000);
	
	$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	$chars = preg_split('//', $alphabet, -1, PREG_SPLIT_NO_EMPTY);
	$len = count($chars) - 1;
	
	$str = '';
	while(strlen($str) < $l){
		$str .= $chars[rand(0, $len)];
	}
	
	return $str;
}

/* Use sessions if session is started / supported */
function hashcash_special_code(){
	$key = session_id();
	
	if(!$key){
		$key = $_SERVER['REMOTE_ADDR'];
	}
	
	return md5($key . ABSPATH . $_SERVER['HTTP_USER_AGENT'] . date("F j, Y, g a"));
}

function hashcash_field_value(){
	global $posts;
	return $posts[0]->ID * strlen(ABSPATH);
}

/* This adds a random hidden field to the form */
function hashcash_add_hidden_tag($page) {
	global $posts, $single;

	if ($single){
		$field_id = hashcash_random_string(rand(6,18));
		$field_name = hashcash_random_string(rand(6,18));
		$form_action = hashcash_random_string(rand(6,18));
		
		// Write in hidden field
		$page = str_replace('<input type="hidden" name="comment_post_ID"', '<input type="hidden" id="' . $field_id . '" name="' . $field_name . '" value="' . hashcash_field_value() . '" /> <input type="hidden" name="comment_post_ID"', $page);
		
		// The form action
		$page = str_replace('<form', '<form onsubmit="' . $form_action . '(\'' . hashcash_special_code() . '\');" ', $page);
		
		// The jscript
		$page = str_replace('</head>', '<script src="' . get_settings('siteurl') . '/wp-content/plugins/md5.js" type="text/javascript"></script><script type="text/javascript"> function ' . $form_action . '(in_str){ eElement = document.getElementById("' . $field_id . '"); if(!eElement){ return false; } else{ eElement.name = hex_md5(in_str); return true; } }</script></head>', $page);
	}
	
	return $page;
}

function hashcash_call_stopgap() {
	ob_start('hashcash_add_hidden_tag');
}

add_action('wp_head', 'hashcash_call_stopgap');

function write_comment_log($comment){
	if ( !HASHCASH_DEBUG || !function_exists('fopen') || !function_exists('fclose') || !function_exists('fwrite') )
		return;
	
	/* Information to write to log */
	$user = array();
	$user[] = date("F j, Y, g:i a");
	$user[] = $_SERVER['REMOTE_ADDR'];
	$user[] = $_SERVER['HTTP_USER_AGENT'];
	$user[] = $_SERVER['HTTP_REFERER'];
	$user[] = $_POST['author'];
	$user[] = $_POST['email'];
	$user[] = $_POST['url'];
	$user[] = preg_replace('/[\n\r]+/','<br />', $comment);
	$user[] = $_POST['comment_post_ID'];

	/* Open the file */
	$path = ABSPATH . "wp-content/plugins/wp-hashcash.log";
	$file = fopen($path, 'a');
	if(!$file){
		die("File \"$path\" failed to open");
	} else{
		$msg  = '';
		for($i = 0; $i < count($user); $i++){
			$msg .= $user[$i] . "\n";
		}
		
		$status = fwrite($file, $msg);
		fclose($file);
		
		if(!status){
			die("Spam-log write failed...");
		}
	}
	
	/* If we're here, the file exists.  Check size, email every 64kb */
	if(filesize($path) > HASHCASH_LOG_SIZE){
		$header = "<html><head><style>tr {	margin: 0px 0px 5px 20px; }</style></head><body><h2>Spam Report:</h2>";
		$footer = "</body></html>";
		$temp = file($path);
		
		if(!$temp){
			die("Unable to open $path for email report...");
		} else{
		
			// Process log
			$log = $header;
			$i = false;
			
			// Get some statistics
			$count = count($temp) / 9;
			$log .= "<p>There were $count spam...</p>";
			
			// Table
			$log .= "<table>";
			for($j = 0; $j < count($temp); $j++){
				if($i){
					$log .= '<tr style="background-color: #eee">';
				} else{
					$log .= '<tr>';
				}

				$log .= "<td>";
				$log .= $temp[$j]; $j++;
				$log .= "<blockquote>";
				$log .= "<strong>IP:</strong> $temp[$j]<br />"; $j++;
				$log .= "<strong>User-Agent:</strong> $temp[$j]<br />"; $j++;
				$log .= "<strong>Referer:</strong> <a href=\"$temp[$j]\">$temp[$j]</a><br />"; $j++;
				$log .= "<strong>Author:</strong> $temp[$j]<br />"; $j++;
				$log .= "<strong>Email:</strong> <a href=\"mailto:$temp[$j]\">$temp[$j]</a><br />"; $j++;
				$log .= "<strong>URL:</strong> <a href=\"$temp[$j]\">$temp[$j]</a><br />"; $j++;
				$log .= "<br />";
				$log .= $temp[$j]; $j++;
				$log .= "<br /><br />";
				$log .= "on post <a href=\"" . get_settings('siteurl') . "/index.php?p=" . $temp[$j] . "\">" . $temp[$j] . "</a>";
				$log .= "</blockquote>";
				$log .="</td>";
				$log .= "</tr>";
				
				$i = !$i;
			}
			$log .= "</table>";
			
			// Footer
			$log .= $footer;
			
			// Send email
			$headers = "Content-type: text/html; charset=" . get_settings('blog_charset') . "\r\n";
			@mail(get_settings('admin_email'), "Spam report for " . get_settings('blogname'), $log, $headers);
			
			// Clear file
			$file = fopen($path, 'w');
			if(!file){
				die("Unable to truncate old log file");
			} else{
				fclose($file);
			}
		}
	}
}

function hashcash_check_hidden_tag($comment) {
	// Our special codes, fixed to check the previous hour
	$special = array();
	$special[] = md5($_SERVER['REMOTE_ADDR'] . ABSPATH . $_SERVER['HTTP_USER_AGENT'] . date("F j, Y, g a"));
	$special[] = md5($_SERVER['REMOTE_ADDR'] . ABSPATH . $_SERVER['HTTP_USER_AGENT'] . date("F j, Y, g a", time()-(60*60)));
	$special[] = md5(session_id() . ABSPATH . $_SERVER['HTTP_USER_AGENT'] . date("F j, Y, g a"));
	$special[] = md5(session_id() . ABSPATH . $_SERVER['HTTP_USER_AGENT'] . date("F j, Y, g a", time()-(60*60)));

	foreach($special as $val){
		if($_POST[md5($val)] == ($_POST['comment_post_ID'] * strlen(ABSPATH) )){
			return $comment;
		}
	}	
	
	if(HASHCASH_DEBUG){
		write_comment_log($comment);
	}

	die();
}

add_filter('post_comment_text', 'hashcash_check_hidden_tag');

?>