<?php
/**
* FloodAssassin - protect your webpage of spam and flood
*
* requires PHP Version 5
*
* Copyright (C) 2008 Benjamin Falk
*
* FloodAssassin is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Text processing
* @package FloodAssassin - protect your webpage of spam and flood
* @author Benjamin Falk
* @copyright 2008 Benjamin Falk
* @license http://www.gnu.org/licenses/gpl.txt GNU GPL Version 3
* @version 0.2
* @link http://projects.citrosaft.com/floodassassin
*/
class FLOODASSASSIN
{
/*
* Default level-values
*/
public $lvContent = 3;
public $lvName = 0.5;
public $lvMail = 0.3;
public $lvIP = 1;
/*
* How much difference has to be between words for readable text
* status? 6 = default
*/
public $readable = 6;
/*
* The following variables are for the connection to a mysql
* database
*/
private $sqlHost = 'localhost';
private $sqlUsername = 'root';
private $sqlPassword = 'root';
private $sqlDatabase = 'floodassassin';
private $sqlTable = 'floodrules';
/*
* The following variables are for the structure of the
* database table
*/
private $sqlContent = 'rule_content';
private $sqlContentCount= 'rule_contentcount';
private $sqlName = 'rule_name';
private $sqlMail = 'rule_mail';
private $sqlIP = 'rule_ip';
private $sqlModifier = 'rule_modifier';
private $sqlContentLv = 'rule_contentlevel';
private $sqlNameLv = 'rule_namelevel';
private $sqlMailLv = 'rule_maillevel';
private $sqlIPLv = 'rule_iplevel';
private $sqlDesc = 'rule_description';
/*
* The current connection
*/
private $sqlConnection = null;
/*
* The $rules-variables get automatically filled.
*/
private $rulesContent = array();
private $rulesContentCount=array();
private $rulesName = array();
private $rulesMail = array();
private $rulesIP = array();
private $rulesModifier = array();
private $rulesContentLv = array();
private $rulesNameLv = array();
private $rulesMailLv = array();
private $rulesIPLv = array();
private $rulesDesc = array();
/*
@ readExternalConfFile - reads an external configuration-file
*/
private function readExternalConfFile($file)
{
if (!file_exists($file))
die('External configuration-file ('.$file.') does not exist');
require_once($file);
$vars = array( 'sqlHost', 'sqlUsername', 'sqlPassword',
'sqlDatabase', 'sqlTable', 'sqlContent',
'sqlContentCount', 'sqlName', 'sqlMail', 'sqlIP',
'sqlModifier', 'sqlContentLv', 'sqlNameLv',
'sqlMailLv');
foreach ($vars as $var)
{ //Check all variables
if (isset($$var))
$this->$var = $$var;
}
return true;
}
/*
@ sqlConnect - create mysql-connection
*/
private function sqlConnect()
{
//Create connection
$this->sqlConnection = mysql_connect($this->sqlHost, $this->sqlUsername, $this->sqlPassword);
if (!$this->sqlConnection || mysql_error())
die(mysql_error());
//Select database
$dbResult = mysql_select_db($this->sqlDatabase);
if (!$dbResult || mysql_error())
die(mysql_error());
}
/*
@ fillRules - get rules
*/
private function fillRules()
{
if ($this->sqlConnection == null) return false;
$dbSql = "SELECT `{$this->sqlContent}`, `{$this->sqlContentCount}`, `{$this->sqlName}`, `{$this->sqlMail}`, `{$this->sqlIP}`, `{$this->sqlModifier}`, `{$this->sqlContentLv}`, `{$this->sqlNameLv}`, `{$this->sqlMailLv}`, `{$this->sqlIPLv}`, `{$this->sqlDesc}` FROM `{$this->sqlTable}`;";
$dbResult = mysql_query($dbSql);
if (mysql_error()) die(mysql_error());
while ($row = mysql_fetch_assoc($dbResult))
{
$row[$this->sqlContent] = $this->replaceVars($row[$this->sqlContent]);
$row[$this->sqlName] = $this->replaceVars($row[$this->sqlName]);
$row[$this->sqlMail] = $this->replaceVars($row[$this->sqlMail]);
$this->rulesContent[] = $row[$this->sqlContent];
$this->rulesContentCount[] = $row[$this->sqlContentCount];
$this->rulesName[] = $row[$this->sqlName];
$this->rulesMail[] = $row[$this->sqlMail];
$this->rulesIP[] = $row[$this->sqlIP];
$this->rulesModifier[] = $row[$this->sqlModifier];
$this->rulesContentLv[] = $row[$this->sqlContentLv];
$this->rulesNameLv[] = $row[$this->sqlNameLv];
$this->rulesMailLv[] = $row[$this->sqlMailLv];
$this->rulesIPLv[] = $row[$this->sqlIPLv];
$this->rulesDesc[] = $row[$this->sqlDesc];
}
}
/*
@ replaceVars - replaces some simple vars into regex
@ $str - contains the regular expression
*/
private function replaceVars($str)
{
$str = str_replace('%link', '(mailto\:|http(s?)\:\/\/|http(s?)\:\/\/www|www){1}[\w\d\.\-]+(.^[\s])*', $str);
$str = str_replace('%mail', '[\w\d\-\.]+[\s]*(@|\[at\])[\s]*[\w\d\-]\.[\w\d\-]+', $str);
preg_match_all('/\%neglook\(\[(.+?)\/([\d]+)\]\)/', $str, $match);
foreach ($match[0] as $i => $s)
{
$part = '';
$chars = $match[1][$i];
$count = intval($match[2][$i]);
if ($count == 1)
$part = $chars;
elseif ($count > 1)
{
$part = '(?i:';
for ($ic=1; $ic<$count; $ic++)
{
$part .= '('.$chars.')(?!';
for ($ii=1; $ii<=$ic; $ii++)
$part .= '\\'.$ii;
$part .= ')';
}
$part .= '('.$chars.'))';
}
$str = str_replace($match[0][$i], $part, $str);
}
return $str;
}
/*
@ __construct - the main-function for initializing the class
@ [$confFile] - an external file for the sql-configuration
@ [$useConnection] - use existing database-connection
*/
public function __construct($confFile=-1, $useConnection=-1)
{
if ($confFile != -1) //Read external configuration, if needed
$this->readExternalConfFile($confFile);
if ($useConnection == -1) $this->sqlConnect();
else $this->sqlConnection = $useConnection;
$this->fillRules();
}
/*
@ checkMessage - the main-function for checking an incomming
@ message
@ $content - contains the content of the given message
@ [$name] - the author of the message
@ [$mail] - email of author
@ [$ip] - the IP of the author
*/
public function checkMessage($content, $name='', $mail='', $ip='')
{
$count = count($this->rulesContent);
$level = array();
$levelDesc = array();
//If the message is empty, it seems, it is spam
if ($content == '') $level = $this->lvContent;
for ($i=0; $i<$count; $i++)
{ //Check message with every rule
if ($this->rulesContentCount[$i] == 0)
{ //Check with basic rule
if ($this->rulesContent[$i] != '' && preg_match('/'.$this->rulesContent[$i].'/'.$this->rulesModifier[$i], $content) == 1)
{ //Check content
$levelDesc[] = $this->rulesDesc[$i];
if ($this->rulesContentLv[$i] != 0)
$level[] = $this->rulesContentLv[$i];
else
$level[] = $this->lvContent;
}
}
else
{ //Check with a counting rule
if ($this->rulesContent[$i] != '' && ($resultCount = preg_match_all('/'.$this->rulesContent[$i].'/'.$this->rulesModifier[$i], $content, $match)) > 0)
{
$baseLevel = $this->rulesContentCount;
$levelDesc[] = $this->rulesDesc[$i].' ('.$resultCount.')';
$level[] = $this->rulesContentCount[$i]*$resultCount;
}
}
if ($name != '')
{ //Check name
if ($this->rulesName[$i] != '' && preg_match('/'.$this->rulesName[$i].'/'.$this->rulesModifier[$i], $name) == 1)
{
$levelDesc[] = $this->rulesDesc[$i];
if ($this->rulesNameLv[$i] != 0)
$level[] = $this->rulesNameLv[$i];
else
$level[] = $this->lvName;
}
}
if ($mail != '')
{ //Check mail
if ($this->rulesMail[$i] != '' && preg_match('/'.$this->rulesMail[$i].'/'.$this->rulesModifier[$i], $mail) == 1)
{
$levelDesc[] = $this->rulesDesc[$i];
if ($this->rulesMailLv[$i] != 0)
$level[] = $this->rulesMailLv[$i];
else
$level[] = $this->lvMail;
}
}
if ($ip != '')
{ //Check ip
if ($this->rulesIP[$i] == $ip)
{
$levelDesc[] = $this->rulesDesc[$i];
if ($this->rulesIPLv[$i] != 0)
$level[] = $this->rulesIPLv[$i];
else
$level[] = $this->lvIP;
}
}
}
//Now check if text is readable
$wordMin = $wordMax = 0;
$smile = false;
$parts = preg_split('/[\s]+/', $content);
foreach ($parts as $part)
{
if (preg_match('/^[\:\$8][\)\w]{1,2}$/', $part) == 1 && $smile == false)
{ //Smile
$levelDesc[] = 'HUMAN EMOTION';
$level[] = -0.2;
$smile = true;
}
else
{ //Word
$words = array($part);
if (strpos($part, '/') !== false)
$words = explode('/', $part); //split inner words
foreach($words as $word)
{
$word = trim($part, ',.:');
$len = strlen($word);
if ($wordMin == 0 || $len < $wordMin)
$wordMin = $len;
if ($len > $wordMax)
$wordMax = $len;
}
}
}
$wordDif = $wordMax-$wordMin;
if ($wordDif >= $this->readable)
{ //Seems to be readable
$level[] = -0.5;
$levelDesc[] = 'READABLE';
}
else
{
$levelDesc[] = 'NOT READABLE';
$level[] = 0.5;
}
$words = count($parts);
if ($words < 3)
{
$levelDesc[] = 'TINY TEXT';
$level[] = 5;
}
elseif ($words < 7)
{
$levelDesc[] = 'SMALL TEXT';
$level[] = 2;
}
//Check if links and email-addresses are in content
preg_match_all('/'.$this->replaceVars('%link').'/', $content, $result);
$count = count($result[0]);
$level[] = $count*0.7;
$levelDesc[] = "LINKS ($count)";
preg_match_all('/'.$this->replaceVars('%mail').'/', $content, $result);
$count = count($result[0]);
$level[] = $count*0.7;
$levelDesc[] = "MAILS ($count)";
return array(array_sum($level), $level, $levelDesc);
}
}
?>
|