<?php

/**
* @desc This report displays the most active visitors
*/
$reports["_SUSPICIOUS_TRAFFIC"] = Array(
	"ClassName" => "SuspiciousTraffic", 
	"Category" => "_PROBLEMS", 
	"icon" => "images/icons/32x32/mostactivevisitors.png",
	"Options" => "daterangeField,profileselector,displaymode,columnSelector",
	"Filename" => "suspicious_traffic",
	"Distribution" => "Premium",
	"Order" => 6,
	"ReportVersion" => 1.0,
	"MinimumVersion" => 3.0,
	"EmailAlerts" => true,
	"canAggregate" => false
);

class SuspiciousTraffic extends Report {

	function Settings() {
		global $reports;

		$this->DefaultDisplay = "table";
		$this->DisplayModes = "table,pie,linechart";
		
		$this->columnDefinitions[] = array("Label" => "_DATE");
		$this->columnDefinitions[] = array("Label" => "Total visitors");
		$this->columnDefinitions[] = array("Label" => "Suspicous visitors");

		$this->help = "This report will find visitors that have less requests with status 200 (successfull) than other status codes (like 404 etc). The theory is that if a visitor is making lots of requests that result in errors, they are probably messing around or probing your site for weaknesses.<br><br>If you want to remove these visitors from your 'human' statistics they will marked as crawlers (as crawl=3)";

		$this->sort = false;
	}
	function DefineQuery() {
		global $gi, $cnames,$db;
		
		
		//1. a bad user can have lots of 404 requests (or non 200)
		//$subquery = "select visitorid, count(*) as hits, count(distinct sessionid) as sessions, sum(IF(status != '200', 1, 0)) as notfound, country from {$this->profile->tablename} where timestamp >= ". $db->quote($this->from) ." and timestamp <= ". $db->quote($this->to) ." group by visitorid having (notfound/hits) >= 0.5 and hits > 2 ";
		//return $subquery;

		//the query above is the basis for the seperatebad function, now lets make one that shpws what we've detected per day, just so we can show that to the user.
		
		$query = "select FROM_UNIXTIME(timestamp, '%d-%b-%Y %a') AS days, visitorid, count(*) as hits, count(distinct sessionid) as sessions, sum(IF(status != '200', 1, 0)) as notfound, country from {$this->profile->tablename} force index(timestamp) where timestamp >= ". $db->quote($this->from) ." and timestamp <= ". $db->quote($this->to) ." group by days,visitorid,country having (notfound/hits) >= 0.5 and hits > 2 order by timestamp";
		//echoWarning($query);
		//$query = "SELECT FROM_UNIXTIME(a.timestamp, '%d-%b-%Y %a') AS days, count(distinct a.visitorid) as total, count(b.visitorid) as bad, count(hits), count(sessions), count(notfound) from {$this->profile->tablename} as a, ({$query}) as b where a.timestamp >= ". $db->quote($this->from) ." and a.timestamp <= ". $db->quote($this->to) ." and FROM_UNIXTIME(a.timestamp, '%d-%b-%Y %a')=b.days group by days order by a.timestamp";
		$bad_query = "select days, count(visitorid) as sus from ($query) as sub group by days";
		//echoWarning($bad_query);
		$good_query = "SELECT FROM_UNIXTIME(a.timestamp, '%d-%b-%Y %a') AS days, count(distinct a.visitorid) as total from {$this->profile->tablename} as a where a.timestamp >= ". $db->quote($this->from) ." and a.timestamp <= ". $db->quote($this->to) ." group by days order by a.timestamp";
		
		$query = "select a.days, total, sus from ($good_query) as a left join ($bad_query) as b on a.days=b.days";

		//2. a bad user could hit the same url over and over
			//$subquery = "select visitorid, count(*) as hits, count(distinct url) as refs, country from {$this->profile->tablename} where timestamp >= ". $db->quote($this->from) ." and timestamp <= ". $db->quote($this->to) ." group by visitorid order by refs asc";
			//$query = "SELECT concat(v.ipnumber,'##',v.visitorid,'##',v.customlabel), hits, refs, country FROM ({$subquery}) as a, {$this->profile->tablename_visitorids} as v where a.visitorid=v.id and (refs/hits) < 0.5";

		//$this->separateBad();

		//echoWarning($query);
		return $query;
	}

	function DisplayReport(){   		
   		if (isset($_REQUEST['movetocrawl']) && $_REQUEST['movetocrawl']=="true") {
   			$this->separateBad();
   		} else {
   			echoNotice("Open settings and choose Yes to remove suspicious traffic");
   		}
   		parent::DisplayReport();  		

 	}

 	function displayCustomForm(){
		echo "<div class='form-group'>";
		echo "<label for='movetocrawl'>Remove Suspicious visitors from human traffic".":</label>";
		echo "<select class='report_option_field form-control' name='movetocrawl' id='movetocrawl'>";
		echo "<option value='false' selected>No</option>";
		echo "<option value='true'>Yes</option>";
		echo "</select>";
		echo "</div>";
	
	}

	function separateBad() {
		global $db, $profile;
		$start = time();
		$db->Execute("CREATE OR REPLACE TABLE  $profile->tablename_crawl like $profile->tablename");
		
		# find visitorids that the user has marked as a bot
		//$q = $db->Execute("select id from $profile->tablename_visitorids where crawl=1");
		$q = $db->Execute("select visitorid, count(*) as hits, sum(IF(status != '200', 1, 0)) as notfound from {$this->profile->tablename} where timestamp >= ". $db->quote($this->from) ." and timestamp <= ". $db->quote($this->to) ." group by visitorid having (notfound/hits) >= 0.5 and hits > 2 ");
		$ids = [];
		while ($data = $q->FetchRow()) {
			$ids[] = $data['visitorid'];
		}
		if (count($ids) > 0) {
			$ids = implode(",",$ids);
			$db->Execute("update $profile->tablename set crawl=3 where visitorid IN ($ids) and timestamp >= ". $db->quote($this->from) ." and timestamp <= ". $db->quote($this->to) ."");
		}
		
		
		# now move all the crawler hits to the crawl table and delete them from the main table
		$db->Execute("insert into $profile->tablename_crawl select * from $profile->tablename where crawl != 0");
		$db->Execute("DELETE FROM {$profile->tablename} WHERE crawl != 0");
				
		
		DeleteDataFiles($this->profile,$this->from,$this->to);
		$took = time() - $start;
		echoNotice("Moving Suspicious Traffic to crawl table took ".number_format($took));
	}
}
?>
