debuggable

 
Contact Us
 

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:

class AkismetTestController extends AppController
{
    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

 
&nsbp;

You can skip to the end and add a comment.

RosSoft  said on Jul 06, 2006:

great model

Daniel Hofstetter said on Jul 06, 2006:

Really nice idea :)

Btw: The first two links do not work.

Konrad said on Jul 06, 2006:

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! :)

Felix Geisendörfer said on Jul 06, 2006:

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) [...]

Tarique Sani said on Jul 09, 2006:

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

Felix Geisendörfer said on Jul 09, 2006:

Tarique, I think every data exchange, be it [database]< ->

or [web service]<->[php] should be handled by a Model. Since you submit and recieve data from Akismet, it falls under this category.


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).

Dieter@be  said on Sep 15, 2006:

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?

Felix Geisendörfer said on Sep 15, 2006:

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?

Dieter@be  said on Sep 16, 2006:

Offcourse that's okay :-)

Dieter@be  said on Sep 18, 2006:

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

Felix Geisendörfer said on Sep 19, 2006:

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*.

Felix Geisendörfer said on Sep 26, 2006:

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.

Chris McConkey  said on Dec 25, 2006:

Hey thanks a million!

Felix Geisendörfer said on Dec 25, 2006:

You're welcome ; )

dirtydeedsdonedirtcheap said on Feb 22, 2007:

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. [...]

kinto  said on May 16, 2007:

I'm successfully using Akismet through your models and I really really really want to thank you! You saved me...

Felix Geisendörfer said on May 18, 2007:

kinto: You are welcome ; ).

Sarah said on Jun 02, 2007:

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.

Jelmer  said on Dec 19, 2007:

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..

Felix Geisendörfer said on Dec 19, 2007:

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.