Remember the days before spam? A CakePHP Model for Akismet
Posted on 5/7/06 by Felix Geisendörfer
Deprecated post
The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.
Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.
Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).
Note: I did a little Online Demo for the stuff explained below, you might want to check it out.
"Remember the days before spam", that's what it reads when you vist akismet.com, and I have to admit, no, I don't remember them ; ). Spam has been an issue for me ever since I got my first email adress. But nowdays spam scripts not only spam standardized applications like wordpress, no, they also try to figure out how to spam your personal contact/guesbook/whatever forms and are pretty good at it.
Here on ThinkingPHP.org, I get about 40~100 spam comments every day, tendency increasing. So at some point the manual deletion and blacklist filters didn't cut it any longer. Gladly, Daniel Hofstetter (Cake Baker) pointed me to a wonderful wordpress plugin called Akismet, which also is a service, dedicated to eliminate spam.
So far I've been really impressed with it. The plugin/service already filtered out 4149 spam comments for me, with no false-positives in them. Only 2 comments made it through their filters. That's a 99,95% accuracy. Truly Amazing! But now here is the best thing, their API is open to the public, and everybody can get a free key over at wordpress.com. However, if you are working on a commercial application you should checkout their restrictions / prices regarding the Commercial Use of API Keys.
Today I finally found the time to get around to write a CakePHP Web Model for their service. It bases on my Web Model class from the Web Model package I'm maintaining. Integration and usage are as simple as it get's. You just download the Web Model, put it in /app/web_model.php and then download the Akismet Model and put it in /app/models/akismet.php.
Now that you have done this, checking a comment for spam is as easy as this:
{
var $name = 'AkismetTest';
var $uses = array('Akismet');
function beforeFilter()
{
$this->Akismet->apiKey = 'your-api-key';
}
function index()
{
$comment = array('comment_author' => 'Spammer Bob',
'comment_author_email' => 'i-spam@mcirosoft.com',
'comment_author' => 'Viagra rocks, dude!');
$result = $this->Akismet->checkComment($comment);
debug($result);
// If the comment is Spam, $result == 'true', if not
// $result == 'false'.
}
}
For a complete list of $comment options, see: http://akismet.com/development/api/#comment-check.
The Model also allows you to manually mark comments as spam and to report false positives. Just take a look at the code , it's pretty self explanatory I hope.
So, I'd be happy to get some feedback from those people who struggle(d) with spam on their (cakephp) sites like I did. Good Luck in the war against spam ; )!
--Felix Geisendörfer aka the_undefined
You can skip to the end and add a comment.
Really nice idea :)
Btw: The first two links do not work.
Thanks,
I was going to "port" this to Cake is ones I got some free time on my hands, but I guess this isn't necessary any more! :)
Hi Daniel, yeah cakephp is a hostname I define locally, so it's not surprising it doesn't work for anybody but me ^^. Anyway, I've corrected the links and set them to the online version, thanks for pointing it out.
And thanks for nice comments. I'd be interested to hear how it works out for you if you use it at some point.
[...] ThinkingPHP » Remember the days before spam? A CakePHP Model for Akismet Felix Geisendörfer has implemented an Askimset spam filter helper for CakePHP (tags: cakephp spam helper) [...]
Wouldn't Akismet be better implemented as a component? Also it need not depend on the web model which in turn depends on curl extension
Writing a private method for doing an http post using sockets specifically for akismet would be trivial and make the component self contained....
Here is the code for a similar function I wrote for some other software
function pp_http_post($request, $host, $path, $port = 80) {
global $pp_user_agent;
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n";
$http_request .= "Content-Length: " . strlen($request) . "\r\n";
$http_request .= "User-Agent: {$pp_user_agent}\r\n";
$http_request .= "\r\n";
$http_request .= $request;
$response = '';
if( false !== ( $fs = fsockopen($host, $port, $errno, $errstr, 30) ) ) {
fwrite($fs, $http_request);
while ( !feof($fs) )
$response .= fgets($fs, 1160); // One TCP-IP packet
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
}
return $response;
}
This in turn has been adapted from the code in word press
Tarique, I think every data exchange, be it [database]< ->
The WebModel depends on the curl extension because it is just the most flexible way to perform the things your browser normally does. This covers POST's/GET's/SSL/Cookies/Headers/etc. So far I've not found a comparable php version to this. But, because I know some people might not have curl, I created the WebModel as an abstract base class for all my web model classes. If you don't like curl, simply replace my WebModel with your own version, and you are done.
Since curl works fine for my local, and all my production enviornments I didn't have the need/time to code a pure php implementation myself, but if you do I'd be glad to include your code in the class. The only requirement I have, is that all the code can be licensed under an MIT style license, since I like to keep my Open Source projects Free Software as well.
Oh and regarding self containment: Yes, I like self contained solutions as well, since they are easier to implement. But my main focus when publishing things here is reusability, which is definitly given by the WebModel class that I've successfully used for several WebModels (RSS, Goggle Analytics & Akismet).
Odd, the "official" akismet plugin replies true or false. your model returns true or 1.
so for those that don't know, that means you need to type === true if you want to check if it's spam (the extra = is for type check)
Also, i wonder what happens in case of unreachable/unresponding askismet servers? i noticed the use of a timeout variable in your web_model. is it safe to assume that if there is no response in this time the askismet-checking aborts and the logic continues to process? and in that case, what will be returned?
Dieter@be: I'll dig into the things you mentioned, and let you know what I found out / if I make changes to the Model itself, ok?
Offcourse that's okay :-)
Okay what i said wasn't 100% correct.
After some testing i found out that what is really returned is this:
'true' (the string, not the boolean), when the hit is true
true (the boolean) when the hit is false
i thought earlier that 1 was also an option but i was mislead cause 1 is what you see when you echo(true);
so to be really sure about the result, this is how i check:
if($is_spam === 'true') echo 'spam';
if($is_spam === true) echo 'not spam';
Still i would love to hear more from you felix, especially about the question what will happen in the case of the unreachable/unresponding askismet server :)
Dieter
Dieter: That sounds like have written some seriously crabby if statement somewhere in there without noticing it. I'll try to get on it tomorrow. In case the server is unreachable the request will timeout and you should get NULL back, but let me check on this before you use it *g*.
Dieter: I am fairly busy right now, if you feel like fixing the error (which should be easy), let me know and I'll update the CakeForge snippet with your tweaks. Other then that I'll start working on HttpSources for Cake 1.2 with nate soon, and at some point do a new implementation of Akismet for this as well.
Hey thanks a million!
You're welcome ; )
cheapticket
[...] Felix Geisendörfer ha infatti realizzato un semplice controller che filtra i commenti inoltrandoli al server di Akismet, e attende la sua risposta per pubblicarli o meno. [...]
I'm successfully using Akismet through your models and I really really really want to thank you! You saved me...
kinto: You are welcome ; ).
On reading your post I had the same thoughts on looking further for a component. Thanks for the explanation on why the code should be a model and not a component. It all makes sense now.
Thanks a lot for this, I'm testing it right now. Lol, kind of ironic to see a spam comment turn up here then, I guess akismet isn't perfect but yeah there is no perfect solution against spam right..
Jelmer: I deleted that comment now. No, it is not perfect, but by far the best there is right now.
This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.
great model