www/adiumxtras.com 53:125992583755: Implement Akismet for spam f...

commits at adium.im commits at adium.im
Fri Feb 27 08:21:27 UTC 2015


details:	http://hg.adium.im/www/adiumxtras.com/rev/125992583755
revision:	53:125992583755
branch:		adiumxtras.com
author:		Thijs Alkemade <me at thijsalkema.de>
date:		Fri Feb 27 09:21:17 2015 +0100

Implement Akismet for spam filtering for adiumxtras comments.

diffs (529 lines):

diff -r 60cf3f31019c -r 125992583755 akismet.class.php
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/akismet.class.php	Fri Feb 27 09:21:17 2015 +0100
@@ -0,0 +1,388 @@
+<?php
+/**
+ * 08.11.2010 22:25:17est
+ * 
+ * Akismet PHP4 class
+ * 
+ * <b>Usage</b>
+ * <code>
+ *    $comment = array(
+ *           'author'    => 'viagra-test-123',
+ *           'email'     => 'test at example.com',
+ *           'website'   => 'http://www.example.com/',
+ *           'body'      => 'This is a test comment',
+ *           'permalink' => 'http://yourdomain.com/yourblogpost.url',
+ *        );
+ *
+ *    $akismet = new Akismet('http://www.yourdomain.com/', 'YOUR_WORDPRESS_API_KEY', $comment);
+ *
+ *    if($akismet->errorsExist()) {
+ *        echo"Couldn't connected to Akismet server!";
+ *    } else {
+ *        if($akismet->isSpam()) {
+ *            echo"Spam detected";
+ *        } else {
+ *            echo"yay, no spam!";
+ *        }
+ *    }
+ * </code>
+ * 
+ * @author Bret Kuhns {@link www.bretkuhns.com}
+ * @link http://code.google.com/p/akismet-php4
+ * @version 0.3.5
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+
+
+// Error constants
+define("AKISMET_SERVER_NOT_FOUND",	0);
+define("AKISMET_RESPONSE_FAILED",	1);
+define("AKISMET_INVALID_KEY",		2);
+
+
+
+// Base class to assist in error handling between Akismet classes
+class AkismetObject {
+	var $errors = array();
+	
+	
+	/**
+	 * Add a new error to the errors array in the object
+	 *
+	 * @param	String	$name	A name (array key) for the error
+	 * @param	String	$string	The error message
+	 * @return void
+	 */ 
+	// Set an error in the object
+	function setError($name, $message) {
+		$this->errors[$name] = $message;
+	}
+	
+
+	/**
+	 * Return a specific error message from the errors array
+	 *
+	 * @param	String	$name	The name of the error you want
+	 * @return mixed	Returns a String if the error exists, a false boolean if it does not exist
+	 */
+	function getError($name) {
+		if($this->isError($name)) {
+			return $this->errors[$name];
+		} else {
+			return false;
+		}
+	}
+	
+	
+	/**
+	 * Return all errors in the object
+	 *
+	 * @return String[]
+	 */ 
+	function getErrors() {
+		return (array)$this->errors;
+	}
+	
+	
+	/**
+	 * Check if a certain error exists
+	 *
+	 * @param	String	$name	The name of the error you want
+	 * @return boolean
+	 */ 
+	function isError($name) {
+		return isset($this->errors[$name]);
+	}
+	
+	
+	/**
+	 * Check if any errors exist
+	 *
+	 * @return boolean
+	 */
+	function errorsExist() {
+		return (count($this->errors) > 0);
+	}
+	
+	
+}
+
+
+
+
+
+// Used by the Akismet class to communicate with the Akismet service
+class AkismetHttpClient extends AkismetObject {
+	var $akismetVersion = '1.1';
+	var $con;
+	var $host;
+	var $port;
+	var $apiKey;
+	var $blogUrl;
+	var $errors = array();
+	
+	
+	// Constructor
+	function AkismetHttpClient($host, $blogUrl, $apiKey, $port = 80) {
+		$this->host = $host;
+		$this->port = $port;
+		$this->blogUrl = $blogUrl;
+		$this->apiKey = $apiKey;
+	}
+	
+	
+	// Use the connection active in $con to get a response from the server and return that response
+	function getResponse($request, $path, $type = "post", $responseLength = 1160) {
+		$this->_connect();
+		
+		if($this->con && !$this->isError(AKISMET_SERVER_NOT_FOUND)) {
+			$request  = 
+					strToUpper($type)." /{$this->akismetVersion}/$path HTTP/1.0\r\n" .
+					"Host: ".((!empty($this->apiKey)) ? $this->apiKey."." : null)."{$this->host}\r\n" .
+					"Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n" .
+					"Content-Length: ".strlen($request)."\r\n" .
+					"User-Agent: Akismet PHP4 Class\r\n" .
+					"\r\n" .
+					$request
+				;
+			$response = "";
+
+			@fwrite($this->con, $request);
+
+			while(!feof($this->con)) {
+				$response .= @fgets($this->con, $responseLength);
+			}
+
+			$response = explode("\r\n\r\n", $response, 2);
+			return $response[1];
+		} else {
+			$this->setError(AKISMET_RESPONSE_FAILED, "The response could not be retrieved.");
+		}
+		
+		$this->_disconnect();
+	}
+	
+	
+	// Connect to the Akismet server and store that connection in the instance variable $con
+	function _connect() {
+		if(!($this->con = @fsockopen($this->host, $this->port))) {
+			$this->setError(AKISMET_SERVER_NOT_FOUND, "Could not connect to akismet server.");
+		}
+	}
+	
+	
+	// Close the connection to the Akismet server
+	function _disconnect() {
+		@fclose($this->con);
+	}
+	
+	
+}
+
+
+
+
+
+// The controlling class. This is the ONLY class the user should instantiate in
+// order to use the Akismet service!
+class Akismet extends AkismetObject {
+	var $apiPort = 80;
+	var $akismetServer = 'rest.akismet.com';
+	var $akismetVersion = '1.1';
+	var $http;
+	
+	var $ignore = array(
+			'HTTP_COOKIE',
+			'HTTP_X_FORWARDED_FOR',
+			'HTTP_X_FORWARDED_HOST',
+			'HTTP_MAX_FORWARDS',
+			'HTTP_X_FORWARDED_SERVER',
+			'REDIRECT_STATUS',
+			'SERVER_PORT',
+			'PATH',
+			'DOCUMENT_ROOT',
+			'SERVER_ADMIN',
+			'QUERY_STRING',
+			'PHP_SELF',
+			'argv'
+		);
+	
+	var $blogUrl = "";
+	var $apiKey  = "";
+	var $comment = array();
+	
+	
+	/**
+	 * Constructor
+	 * 
+	 * Set instance variables, connect to Akismet, and check API key
+	 * 
+	 * @param	String	$blogUrl	The URL to your own blog
+	 * @param 	String	$apiKey		Your wordpress API key
+	 * @param 	String[]	$comment	A formatted comment array to be examined by the Akismet service
+	 * @return	Akismet
+	 */
+	function Akismet($blogUrl, $apiKey, $comment = array()) {
+		$this->blogUrl = $blogUrl;
+		$this->apiKey  = $apiKey;
+		$this->setComment($comment);
+		
+		// Connect to the Akismet server and populate errors if they exist
+		$this->http = new AkismetHttpClient($this->akismetServer, $blogUrl, $apiKey);
+		if($this->http->errorsExist()) {
+			$this->errors = array_merge($this->errors, $this->http->getErrors());
+		}
+		
+		// Check if the API key is valid
+		if(!$this->_isValidApiKey($apiKey)) {
+			$this->setError(AKISMET_INVALID_KEY, "Your Akismet API key is not valid.");
+		}
+	}
+	
+	
+	/**
+	 * Query the Akismet and determine if the comment is spam or not
+	 * 
+	 * @return	boolean
+	 */
+	function isSpam() {
+		$response = $this->http->getResponse($this->_getQueryString(), 'comment-check');
+		
+		return ($response == "true");
+	}
+	
+	
+	/**
+	 * Submit this comment as an unchecked spam to the Akismet server
+	 * 
+	 * @return	void
+	 */
+	function submitSpam() {
+		$this->http->getResponse($this->_getQueryString(), 'submit-spam');
+	}
+	
+	
+	/**
+	 * Submit a false-positive comment as "ham" to the Akismet server
+	 *
+	 * @return	void
+	 */
+	function submitHam() {
+		$this->http->getResponse($this->_getQueryString(), 'submit-ham');
+	}
+	
+	
+	/**
+	 * Manually set the comment value of the instantiated object.
+	 *
+	 * @param	Array	$comment
+	 * @return	void
+	 */
+	function setComment($comment) {
+		$this->comment = $comment;
+		if(!empty($comment)) {
+			$this->_formatCommentArray();
+			$this->_fillCommentValues();
+		}
+	}
+	
+	
+	/**
+	 * Returns the current value of the object's comment array.
+	 *
+	 * @return	Array
+	 */
+	function getComment() {
+		return $this->comment;
+	}
+	
+	
+	/**
+	 * Check with the Akismet server to determine if the API key is valid
+	 *
+	 * @access	Protected
+	 * @param	String	$key	The Wordpress API key passed from the constructor argument
+	 * @return	boolean
+	 */
+	function _isValidApiKey($key) {
+		$keyCheck = $this->http->getResponse("key=".$this->apiKey."&blog=".$this->blogUrl, 'verify-key');
+			
+		return ($keyCheck == "valid");
+	}
+	
+	
+	/**
+	 * Format the comment array in accordance to the Akismet API
+	 *
+	 * @access	Protected
+	 * @return	void
+	 */
+	function _formatCommentArray() {
+		$format = array(
+				'type' => 'comment_type',
+				'author' => 'comment_author',
+				'email' => 'comment_author_email',
+				'website' => 'comment_author_url',
+				'body' => 'comment_content'
+			);
+		
+		foreach($format as $short => $long) {
+			if(isset($this->comment[$short])) {
+				$this->comment[$long] = $this->comment[$short];
+				unset($this->comment[$short]);
+			}
+		}
+	}
+	
+	
+	/**
+	 * Fill any values not provided by the developer with available values.
+	 *
+	 * @return	void
+	 */
+	function _fillCommentValues() {
+		if(!isset($this->comment['user_ip'])) {
+			$this->comment['user_ip'] = ($_SERVER['REMOTE_ADDR'] != getenv('SERVER_ADDR')) ? $_SERVER['REMOTE_ADDR'] : getenv('HTTP_X_FORWARDED_FOR');
+		}
+		if(!isset($this->comment['user_agent'])) {
+			$this->comment['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
+		}
+		if(!isset($this->comment['referrer'])) {
+			$this->comment['referrer'] = $_SERVER['HTTP_REFERER'];
+		}
+		if(!isset($this->comment['blog'])) {
+			$this->comment['blog'] = $this->blogUrl;
+		}
+	}
+	
+	
+	/**
+	 * Build a query string for use with HTTP requests
+	 *
+	 * @access	Protected
+	 * @return	String
+	 */
+	function _getQueryString() {
+		foreach($_SERVER as $key => $value) {
+			if(!in_array($key, $this->ignore)) {
+				if($key == 'REMOTE_ADDR') {
+					$this->comment[$key] = $this->comment['user_ip'];
+				} else {
+					$this->comment[$key] = $value;
+				}
+			}
+		}
+
+		$query_string = '';
+
+		foreach($this->comment as $key => $data) {
+			$query_string .= $key . '=' . urlencode(stripslashes($data)) . '&';
+		}
+
+		return $query_string;
+	}
+	
+	
+}
+?>
\ No newline at end of file
diff -r 60cf3f31019c -r 125992583755 xtras.php
--- a/xtras.php	Thu Feb 26 08:26:52 2015 +0100
+++ b/xtras.php	Fri Feb 27 09:21:17 2015 +0100
@@ -61,58 +61,82 @@
 		break;
 
 		case "add_comment":
-            require_once('../recaptcha_keys.php');
+			require_once('../recaptcha_keys.php');
 			require_once('recaptchalib.php');
+			require_once('akismet.class.php');
 			$resp = recaptcha_check_answer (RECAPTCHA_PRIV_KEY,
 											$_SERVER["REMOTE_ADDR"],
 											NULL,
 											$_POST["g-recaptcha-response"]);
 			if ($resp->is_valid) {
-				if ($_POST['comment'] && $_POST['xtra_id']) {
-					if (currentUID()) {
-						$sql->query("INSERT INTO comments (xtra_id, parent_id, comment, user_id, posted) VALUES ('%d', '%d', '%s', '%d', NOW())", intval($_POST['xtra_id']), intval($_POST['parent_id']), strip_tags($_POST['comment']), currentUID());
-						$newCommentID = $sql->insert_id();
+
+				$akismet = NULL;
+
+				if ($currentUID && $_POST['xtra_id'] && $_POST['comment']) {
+					$sql->query("SELECT users.username, users.email, users.website FROM users WHERE users.user_id = '%d'", currentUID());
+
+					$user = $sql->fetch_assoc();
+
+					$comment = array(
+							'author'    => $user['username'],
+							'email'     => $user['email'],
+							'website'   => $user['website'],
+							'body'      => $_POST['comment'],
+							'permalink' => sprintf("http://www.adiumxtras.com/index.php?a=xtras&xtra_id=%d", $_POST['xtra_id'])
+						);
 					
-						// Email the author about the new comment.
-						$sql->query("SELECT xtras.title, users.username, users.email FROM xtras, users WHERE xtras.user_id=users.user_id AND xtras.xtra_id='%d'", intval($_POST['xtra_id']));
-						$emailInfo = $sql->fetch_assoc();
-						$message = sprintf("%s\n\nA new comment has been added to one of your xtras.\n\n", $emailInfo['username']);
-						$message .= sprintf("*******************\n%s\n<http://adiumxtras.com/index.php?a=xtras&xtra_id=%d#c%d>\n*******************\n\n", $emailInfo['title'], $_POST['xtra_id'], $newCommentID);
-						$message .= sprintf("Comment by: %s\n\nComment:\n\n%s", $_COOKIE['xtras_user'], $_POST['comment']);
+					$akismet = new Akismet('http://www.adiumxtras.com/', AKISMET_API_KEY, $comment);
+				}
 						
-						mail($emailInfo['email'], "New Comment on Xtras", $message, "From: xtras at adiumxtras.com");
-					
-						if ($_POST['parent_id']) {
-							$emails = array();
-							$sql->query("SELECT comments.*, users.* FROM comments, users WHERE comments.comment_id IN (%s) AND users.user_id = comments.user_id", implode(",", commentsWithParent(intval($_POST['parent_id']))));
-							while ($row = $sql->fetch_assoc()) {
-								if ($row['email'] == $emailInfo['email'] || $row['comment_id'] == $newCommentID)
-									continue;
-								$emails[] = $row['email'];
+				if($akismet && ($akismet->errorsExist() || !$akismet->isSpam())) {
+
+					if ($_POST['comment'] && $_POST['xtra_id']) {
+						if (currentUID()) {
+
+							$sql->query("INSERT INTO comments (xtra_id, parent_id, comment, user_id, posted) VALUES ('%d', '%d', '%s', '%d', NOW())", intval($_POST['xtra_id']), intval($_POST['parent_id']), strip_tags($_POST['comment']), currentUID());
+							$newCommentID = $sql->insert_id();
+						
+							// Email the author about the new comment.
+							$sql->query("SELECT xtras.title, users.username, users.email FROM xtras, users WHERE xtras.user_id=users.user_id AND xtras.xtra_id='%d'", intval($_POST['xtra_id']));
+							$emailInfo = $sql->fetch_assoc();
+							$message = sprintf("%s\n\nA new comment has been added to one of your xtras.\n\n", $emailInfo['username']);
+							$message .= sprintf("*******************\n%s\n<http://adiumxtras.com/index.php?a=xtras&xtra_id=%d#c%d>\n*******************\n\n", $emailInfo['title'], $_POST['xtra_id'], $newCommentID);
+							$message .= sprintf("Comment by: %s\n\nComment:\n\n%s", $_COOKIE['xtras_user'], $_POST['comment']);
+							
+							mail($emailInfo['email'], "New Comment on Xtras", $message, "From: xtras at adiumxtras.com");
+						
+							if ($_POST['parent_id']) {
+								$emails = array();
+								$sql->query("SELECT comments.*, users.* FROM comments, users WHERE comments.comment_id IN (%s) AND users.user_id = comments.user_id", implode(",", commentsWithParent(intval($_POST['parent_id']))));
+								while ($row = $sql->fetch_assoc()) {
+									if ($row['email'] == $emailInfo['email'] || $row['comment_id'] == $newCommentID)
+										continue;
+									$emails[] = $row['email'];
+								}
+		
+								$emails = array_unique($emails);
+								
+								foreach ($emails as $email) {
+									$message = sprintf("Hello:\n\nA new comment has been added to a comment thread that you are participating in:\n\n");
+									$message .= sprintf("*******************\n%s\n<http://adiumxtras.com/index.php?a=xtras&xtra_id=%d#c%d>\n*******************\n\n", $emailInfo['title'], $_POST['xtra_id'], $newCommentID);
+									$message .= sprintf("Comment by: %s\n\nComment:\n\n%s", $_COOKIE['xtrauser'], $_POST['comment']);
+									mail($email, "New Comment on Xtras Thread", $message, "From: xtras at adiumxtras.com");
+								}
 							}
-	
-							$emails = array_unique($emails);
-							
-							foreach ($emails as $email) {
-								$message = sprintf("Hello:\n\nA new comment has been added to a comment thread that you are participating in:\n\n");
-								$message .= sprintf("*******************\n%s\n<http://adiumxtras.com/index.php?a=xtras&xtra_id=%d#c%d>\n*******************\n\n", $emailInfo['title'], $_POST['xtra_id'], $newCommentID);
-								$message .= sprintf("Comment by: %s\n\nComment:\n\n%s", $_COOKIE['xtrauser'], $_POST['comment']);
-								mail($email, "New Comment on Xtras Thread", $message, "From: xtras at adiumxtras.com");
-							}
+											
+							// Send the person back to whence-forth they came.					
+							header(sprintf("Location: index.php?a=xtras&xtra_id=%d", $_POST['xtra_id']));
+						} else {
+							// There was code in the old version for anonymous posting.
+							// I'm totally not replicating it.
+							$smarty->assign("message", "Somehow you submitted the form without logging in. That's neat. But, first, you must login.");
+							$smarty->display("loginForm.tpl");
 						}
-										
-						// Send the person back to whence-forth they came.					
+					} else
 						header(sprintf("Location: index.php?a=xtras&xtra_id=%d", $_POST['xtra_id']));
-					} else {
-						// There was code in the old version for anonymous posting.
-						// I'm totally not replicating it.
-						$smarty->assign("message", "Somehow you submitted the form without logging in. That's neat. But, first, you must login.");
-						$smarty->display("loginForm.tpl");
-					}
-				} else
-					header(sprintf("Location: index.php?a=xtras&xtra_id=%d", $_POST['xtra_id']));
-				break;
-			} // intentional fallthrough, they failed the captcha, but let's be nice and allow them to try again
+					break;
+				}
+			} // intentional fallthrough, they failed the captcha or the akismet test, but let's be nice and allow them to try again
 		
 		default:
 			$sql->query("SELECT xtras.*, cats.*, users.*, UNIX_TIMESTAMP(xtras.date_added) AS date_added, UNIX_TIMESTAMP(xtras.bin_updated) AS bin_updated, xtras.status as status FROM xtras, cats, users, assoc WHERE xtras.xtra_id=assoc.xtra_id AND xtras.user_id=users.user_id AND cats.cat_id = assoc.cat_id AND xtras.xtra_id='%d'", intval($_GET['xtra_id']));
@@ -188,7 +212,7 @@
 					$smarty->assign("old_comment", '');
 					$smarty->assign("error", '');
 				}
-                require_once('../recaptcha_keys.php');
+				require_once('../recaptcha_keys.php');
 				require_once('recaptchalib.php');
 				$smarty->assign("recaptcha_html", recaptcha_get_html(RECAPTCHA_PUB_KEY));
 				$smarty->display("xtras.tpl");




More information about the commits mailing list