PHP Badword Filter (Intermediate)

Reply

Join Date: Jul 2007
Posts: 1
Reputation: esp68 is an unknown quantity at this point 
Solved Threads: 0
esp68 esp68 is offline Offline
Newbie Poster

PHP Badword Filter (Intermediate)

 
0
  #1
Jul 23rd, 2007
Yes, there are many posts out there about badword filters, and most seem to fall short of something you'd want to turn loose on a corporate website. I've created a fairly elegant badword solution, and I wish to share it with the development community. I'm looking to optimize it a bit more, because as the list of badwords I use grows, the process time could get pretty ugly.

A little more explanation about this particular script - One of my clients has a fairly complex comment form on their website that allows the option to comment, get the newsletter, etc - and then emails the necessary details to their person who handles such things. Recently, the emails were coming fast and furious with spam for lewd websites, prescription medications, and such. Of course, this needed to stop.

As there is no message board to check, and no obvious verification to see if the message was indeed sent or received (just a static thank-you splash page) - there was no need to try and replace bad words with characters, or warn the offending user/bot that anything was amiss - the messages just needed to be sent to the circular bin. As we weren't interested in keeping the messages around, a little delicacy was needed to keep partial matches from flagging the messages. This was the first feature of my script that I noticed most do not contain - many will display words like class as cl***. As the message would then be flagged as containing bad words, this approach wouldn't work.

So, a little wrangling with regular expressions later, I have a script that only matches whole words from my badwords list. Now, the occasional swear isn't going to matter, so if a couple masked words or swears next to tags make it through, it's ok. If you need to further filter for those instances, then by all means replace tags with whitespace before doing the string comparison.

Other features that are in this script that may or may not be included in other examples bouncing around the web:

* bad words are loaded from a text file
* additional block for [url] tags implemented
* result is transparent - offender doesn't know he's blocked.

And here's the script. If there are ideas on how to tidy some things up, I'll happily give them a shot. I'm currently considering switching from preg_match() to eregi(), and also creating the badwords expression from the entire badwords file, using the | operator and a loop. This way there's only one preg_match() call needed, instead of looping it. I'm also sure some of my control expressions could be a little more elegant, but this is a good first crack, I believe. If I make any major changes, I'll post them as replies.


  1. // Filtering Function
  2.  
  3. function filterBadWords($str,$badWordsFile) {
  4. $badFlag = 0;
  5. if(!is_file($badWordsFile)) {
  6. echo "ERROR: file missing: ".$badWordsFile;
  7. exit;
  8. }
  9. else {
  10. $badWordsFH = fopen($badWordsFile,"r");
  11. $badWordsArray = explode("\n", fread($badWordsFH, filesize($badWordsFile)));
  12. fclose($badWordsFH);
  13. }
  14. foreach ($badWordsArray as $badWord) {
  15. if(!$badWord) continue;
  16. else {
  17. $regexp = "/\b".$badWord."\b/i";
  18. if(preg_match($regexp,$str)) $badFlag = 1;
  19. }
  20. }
  21. if(preg_match("/\[url/",$str)) $badFlag = 1;
  22. return $badFlag;
  23. }

  1. // Function Call/Usage
  2. if (filterBadWords($message,"badwords.txt") == 0) {
  3. mail("mail@destination.com", $subject, $message, $from);
  4. }
  5. header("Location: http://www.siteurl.com/index.php?p=Thank_You");


  1. // badwords.txt
  2. word1
  3. word2
  4. word3
Reply With Quote Quick reply to this message  
Join Date: Apr 2007
Posts: 136
Reputation: dr4g is an unknown quantity at this point 
Solved Threads: 5
dr4g's Avatar
dr4g dr4g is offline Offline
Junior Poster

Re: PHP Badword Filter (Intermediate)

 
0
  #2
Jul 24th, 2007
A better solution for yourself would be just to mask the bad words (unless you really don't want to send the email).

Just do a preg_replace of *@!>&^ (or however many characters are in the badword).

Nothing much wrong with your code though, just a few logic changes might benefit yourself.

You are not validating your mail() function either. I suggest wrapping it in an IF statement or use the @ character eg: @mail(..);

Cheers
GardCMS :: Open Source CMS :: Gardcms.org
Reply With Quote Quick reply to this message  
Join Date: Jun 2009
Posts: 1
Reputation: jiawei456123 is an unknown quantity at this point 
Solved Threads: 0
jiawei456123 jiawei456123 is offline Offline
Newbie Poster

Re: PHP Badword Filter (Intermediate)

 
-1
  #3
Jun 21st, 2009
Originally Posted by esp68 View Post
Yes, there are many posts out there about badword filters, and most seem to fall short of something you'd want to turn loose on a corporate website. I've created a fairly elegant badword solution, and I wish to share it with the development community. I'm looking to optimize it a bit more, because as the list of badwords I use grows, the process time could get pretty ugly.

A little more explanation about this particular script - One of my clients has a fairly complex comment form on their website that allows the option to comment, get the newsletter, etc - and then emails the necessary details to their person who handles such things. Recently, the emails were coming fast and furious with spam for lewd websites, prescription medications, and such. Of course, this needed to stop.

As there is no message board to check, and no obvious verification to see if the message was indeed sent or received (just a static thank-you splash page) - there was no need to try and replace bad words with characters, or warn the offending user/bot that anything was amiss - the messages just needed to be sent to the circular bin. As we weren't interested in keeping the messages around, a little delicacy was needed to keep partial matches from flagging the messages. This was the first feature of my script that I noticed most do not contain - many will display words like class as cl***. As the message would then be flagged as containing bad words, this approach wouldn't work.

So, a little wrangling with regular expressions later, I have a script that only matches whole words from my badwords list. Now, the occasional swear isn't going to matter, so if a couple masked words or swears next to tags make it through, it's ok. If you need to further filter for those instances, then by all means replace tags with whitespace before doing the string comparison.

Other features that are in this script that may or may not be included in other examples bouncing around the web:

* bad words are loaded from a text file
* additional block for [url] tags implemented
* result is transparent - offender doesn't know he's blocked.

And here's the script. If there are ideas on how to tidy some things up, I'll happily give them a shot. I'm currently considering switching from preg_match() to eregi(), and also creating the badwords expression from the entire badwords file, using the | operator and a loop. This way there's only one preg_match() call needed, instead of looping it. I'm also sure some of my control expressions could be a little more elegant, but this is a good first crack, I believe. If I make any major changes, I'll post them as replies.


  1. // Filtering Function
  2.  
  3. function filterBadWords($str,$badWordsFile) {
  4. $badFlag = 0;
  5. if(!is_file($badWordsFile)) {
  6. echo "ERROR: file missing: ".$badWordsFile;
  7. exit;
  8. }
  9. else {
  10. $badWordsFH = fopen($badWordsFile,"r");
  11. $badWordsArray = explode("\n", fread($badWordsFH, filesize($badWordsFile)));
  12. fclose($badWordsFH);
  13. }
  14. foreach ($badWordsArray as $badWord) {
  15. if(!$badWord) continue;
  16. else {
  17. $regexp = "/\b".$badWord."\b/i";
  18. if(preg_match($regexp,$str)) $badFlag = 1;
  19. }
  20. }
  21. if(preg_match("/\[url/",$str)) $badFlag = 1;
  22. return $badFlag;
  23. }

  1. // Function Call/Usage
  2. if (filterBadWords($message,"badwords.txt") == 0) {
  3. mail("mail@destination.com", $subject, $message, $from);
  4. }
  5. header("Location: http://www.siteurl.com/index.php?p=Thank_You");


  1. // badwords.txt
  2. word1
  3. word2
  4. word3
I tried the above mentioned code but it does not work, only the last bad word in the txt file would be filtered

my additional code in front is this
  1. $badWordsFile="badwords.txt";
in addition, i replace all $str with $message but it does not work, I am currently rushing a project and i need an urgent reply, thanks!
Last edited by jiawei456123; Jun 21st, 2009 at 2:09 am. Reason: Spelling error
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:



Similar Threads
Other Threads in the PHP Forum
Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC