Forum Moderators: coopster & phranque

Message Too Old, No Replies

@badwords expert badly needed

Wow! 4-days and it still won’t work ):

         

bsd4me

5:23 am on Dec 1, 2002 (gmt 0)

10+ Year Member



Hi all.

Can you believe I've been at this for 4-days! I grabbed this simple little subroutine to add to my form based email handler, which is supposed to block bad words, due to some problems we've been having. After 56 variations of adding this routine to the script, it STILL won't work properly!

It either doesn't work at all, or it displays the 'bad words error' for "all" messages trying to pass through it. It really p's me off, as I know it's something really stupid, but for the life of me, I can't figure it out. I've posted the script here so you can see how I've configured it.

I've commented the @badwords portions in BIG bold letters with ###### comments on each side of them ###### Any fix someone could add would be so much appreciated.

#!/usr/local/bin/perl

$mailprog = '/usr/sbin/sendmail';

# What operating system are we on?
$os = "UNIX"; # enter: "WINDOWS" for NT or 95 machines.

# list of e-mail addresses
@email_list = ("admin\@mysite.com");

############################################################

@AUTHURLS = ('http://mysite.com');

# Check to make sure this script was called by an authorized URL(s)

&check_url;

sub check_url
{
if ($ENV{'HTTP_REFERER'})
{
foreach $AUTHURL (@AUTHURLS)
{
if ($ENV{'HTTP_REFERER'} =~ /$AUTHURL/i)
{
$check_url = '1';
last;
}
}
}
else
{
$check_url = '1';
}

if ($check_url!= 1)
{
print "Content-type: text/html\n\n";
print "<html>\n <head>\n <title>Unauthorized URL Referrer - Access Denied</title>\n </head>\n";
print "</body></html>\n";
exit;
}

}

read(STDIN, $input, $ENV{'CONTENT_LENGTH'});

@pairs = split(/&/, $input);

foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);

$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

$FORM{$name} = $value;
}

# Lets translate our hash variables
$recipient = $FORM{'recipient'};
$message = $FORM{'message'};
$fromwho = $FORM{'fromwho'};
$fromname = $FORM{'fromname'};
$subject = $FORM{'subject'};
$phone = $FORM{'phone'};

#################### BEGIN BADWORDS MAIN ROUTINE ########################################

&check_badwords; # Tried 40 variations of this

# The @badwords array contains the list of "bad words" that you want to prevent
@badwords = ("badword1", "badword2", "badword3", "badword4");
sub check_badwords {
$badwords="on";
@check_fields = ("message", "fromwho", "fromname", "subject");
foreach $badword (@badwords) {
foreach $check_field (@check_fields) {
if ($FORM{$check_field} =~ /$badword/) {
$badwords="on";
}
}
}
if ($badwords eq "on") {
&badwords_error;
exit;
}
}

&badwords_error if $check_field; # Tried 20 variations of this

#################### END BADWORDS MAIN ROUTINE ########################################


# Get rid of blank lines
# this fixes the bug of wierd blank lines
# $message =~ s/\cM//g;
# $message =~ s/\n/ /g;

# Check fields
&missing(message) unless $message;
&missing(your_email_address) unless $fromwho;
&missing(subject) unless $subject;

# What we have to do

&getdate;

if($log eq "yes") {
&LogIt;
}

if ($os eq "UNIX") {
&SendIt;
} else {
require "winmail.pl";
&SendMail($mailprog, $tempdirectory, $subject,
$email_list[$recipient], $message);
}

&PrintResponse;


# functions #

sub SendIt {
open (MAIL, "¦$mailprog -t") ¦¦ die $!;
print MAIL "To: $email_list[$recipient]\n";
print MAIL "From: $fromname <$fromwho>\n";
print MAIL "Subject: $subject\n";
print MAIL "$message\n";
print MAIL "\n";
print MAIL "Phone Number: $phone\n";
print MAIL "\n";
print MAIL "<REMOTE HOST> $ENV{'REMOTE_HOST'}\n";
print MAIL "<REMOTE ADDRESS> $ENV{'REMOTE_ADDR'}\n";
print MAIL "<USER AGENT> $ENV{'HTTP_USER_AGENT'}\r\n";
close(MAIL);
}

sub LogIt {

open(DATA, "$data") ¦¦ die $!;
$number = <DATA>;
close(DATA);

$number++;

open(DATA, ">$data") ¦¦ die $!;
print DATA "$number";
close(DATA);

open (FILE, ">>$logfile") ¦¦ die $!;
print FILE "$email_list[$recipient]&&$fromwho&&$fromname&&$subject&&$message&&$date&&$number\n";
close(FILE);
}

sub getdate {

@days = ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
@months = ('January','Feburary','March','April','May','June','July','August','September',
'October','November','December');

($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
if($hour < 10) { $hour = "0$hour"; }
if ($min < 10) { $min = "0$min"; }
if ($sec < 10) { $sec = "0$sec"; }

$date = "$days[$wday], $months[$mon] $mday, 19$year";
}

sub PrintResponse {
print "Content-type: text/html\n\n";
print <<"END"
<html>

<head>
<title>Thanks!</title>

</head>

<body>
<p><font size=6>Thanks!</font></p>
<p><a href="http://www.mysite.com">Return to Mysite.com</a></p>
</body>

</html>

END

}

sub missing {
local($what) = @_;

print "Content-type: text/html\n\n";
print "<HTML><HEAD><TITLE>You Forgot: $what</TITLE></HEAD>\n";
print "<BODY>\n";
print "You forgot to fill out: <b>$what</b>\n";
print "<br><br>\n";
print "Please go back and try again!\n";
print "</BODY></HTML>\n";
exit;
}

#################### Start BADWORDS SUBROUTINE ########################################

sub badwords_error {
print "Content-type: text/html\n\n";
print "<html><head><title>ERROR: Bad Words Found!</title></head>\n";
print "<body bgcolor=#FFFFFF text=#000000>";
print "<center><h1>Bad Words Found!</h1></center>\n";
print "Please keep our website clean by refraining from using vulgar words!";
print "</form></body></html>\n";
exit;
}

#################### END BADWORDS SUBROUTINE ########################################

Thanks for taking the time to view this,

Dave

gsx

12:03 pm on Dec 1, 2002 (gmt 0)

10+ Year Member



1) You are setting badwords to "on", then if you find a badword you are setting it to "on"? Then you check if badwords is "on" (it's not going to be anything else), and shoot off to the error in all circumstances. I think you mean to set badwords to "off" in the initialisation of that variable.

2) You are checking /$badwords/ and not /$badwords/i, the i on the end will make the check case-insensitive.

bsd4me

7:01 pm on Dec 1, 2002 (gmt 0)

10+ Year Member



Thanks GSX.

I wasn’t sure about that one, so I did the foolish thing, which was setting everything to on. I just did as you suggested, then tried a bunch of different variations, yet still nothing. I just don’t get it… It’s such a simple snippet, and by all accounts should work as configured here.

I tried it with and without &check_badwords; , but nothing. It just goes through the typical routine and processes the forums input; ignoring the @badwords ):

This is what I have now:

------------------------------------

&check_badwords;

# The @badwords array contains the list of "bad words" that you want to prevent
@badwords = ("f-word", "s-word", "a-word", "etc");
sub check_badwords {
$badwords="off";
@check_fields = ("message", "fromwho", "fromname", "subject");
foreach $badword (@badwords) {
foreach $check_field (@check_fields) {
if ($FORM{$check_field} =~ /$badword/) {
$badwords="on";
}
}
}
if ($badwords eq "on") {
&badwords_error;
exit;
}
}

bsd4me

7:25 pm on Dec 1, 2002 (gmt 0)

10+ Year Member



Got it!

&check_badwords; was in the wrong place :)

Thanks,

Dave

Josk

10:32 am on Dec 2, 2002 (gmt 0)

10+ Year Member



Why not use $badwords = 0, $badwords = 1 when you find a swearword?

eg:

if($badwords)
{
print "wash your mouth out";
}

Makes for less typing.

andreasfriedrich

3:45 pm on Dec 2, 2002 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



$match = join ' ¦¦ ', map { "/\\b\$badwords[$_]\\b/o" } 0..@#badwords; 
$match = eval "sub { $match }";
foreach (@check_fields) {
$badwords++, last if &$match;
}
print 'you naughty little chap ;)' if $badwords;

might be even more efficient.

Andreas

bsd4me

10:57 pm on Dec 4, 2002 (gmt 0)

10+ Year Member



Thanks Andreas and everyone else for the help. I got it working and it does an excellent job. In addition, I added a 5-minute delay feature to block dopes that feel they must send a duplicate email to every contact on the drop down menu. Ya know.. They hit the back button, and select another contact until they’ve covered the whole list.

One thing I wanted to add to the above recipe was this:

#adds characters between letters of the words to check
#and see if clever users entered words like "poop" or
# "p!o!o!p" to get around the badword checking.

&BadListCheck(' ');
&BadListCheck('\s+');
&BadListCheck('-');
&BadListCheck(',');
&BadListCheck('.');
&BadListCheck('\!');
}
if (@BadWordFound)
{
$BadFound = 1;
}
else
{
$BadFound = 0;
}
}

#bad list check is a part of my cussing subroutine.
sub BadListCheck
{
$InsertString = join(//, @_);
foreach (@badwords)
{
@NewBad = split(//, $_);
$TheNewBad = join("$InsertString", @NewBad);
if ($CheckString =~ /$TheNewBad/gi)
{
push (@BadWordFound, $_);
}
}
}

hehe.. I changed the badword example at the top, as I don’t want to offend the forum :) The problem is, I can’t seem to figure out where or what I would change in my above script to integrate this snippet. Everything I tried resulted in a 500 error, and even when I got rid of those, it still wouldn’t block b-a-d-w-o-r-d-s. It’s not a big deal, but if someone knows of an easy way to slide this in, that’d be great.

In case you’re all wondering why I’m going to all this trouble to filter email, I find that it saves considerable nonsense and time- something I don’t have a lot of. So far, I’ve managed to substantially decrease whimsical or waste-of-time type messages by doing away with them in the first place, thus allowing more resources to be diverted to legitimate client inquires :) It's sort of the same thing I do with Procmail.

Dave

andreasfriedrich

11:09 pm on Dec 4, 2002 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



How about just removing those characters between letters prior to checking for bad words.

Andreas