<?php

	/*
		File:		banlist.cls.php

		Auteur:		ME Wieringa, 
		Email:		pholeron@hotmail.com
		Website:	http://www.pholeron.nl

		Naam:		PHP Banlist
		Versie:		1.0
		Datum:		13-3-2006


		Deze class verwerkt een FILE-based banlijst. Met deze class wordt het eenvoudig(er) om IP 
		adressen te blokkeren op PHP pagina's. Een banlijst zou bijvoorbeeld gebruikt kunnen worden 
		om te voorkomen dat bezoekers een formulier hacken.

		Note: Gezien vrijwel alle bezoekers een dynamisch IP adres hebben heeft het geen zin om een
		IP adres voor (al te) lange tijd te blokkeren.



		De volgende functies uit de class kunnen geintegreerd worden in je PHP code:

		Banlist([BAN_TIME[, FILEPATH]])

			- Dit is de constructor van de class. Je kunt de 'default' bantijd in uren aangeven 
			  (dit mag een decimaal getal zijn). Standaard staat de bantijd op 2 uur.
			- Je kunt het bestand opgeven waarin de banlijst wordt bewaard (zorg dat dit bestand 
			  bestaat en dat PHP lees- en schrijfrechten heeft op het bestand). Standaard wordt
			  als pad 'banlist.csv' gebruikt.


		add([IP[, DATE]])

			- Deze functie voegt een nieuw IP adres toe aan de banlijst. Indien het adres al 
			  bestaat wordt alleen de bantijd aangepast. Als er geen IP is opgegeven, wordt het 
			  IP van de huidige bezoeker gebruikt.
			- Als er een datum wordt opgegeven, wordt deze datum gebruikt voor het instellen van 
			  de bantijd. Anders wordt de 'standaard' bantijd gebruikt die was ingesteld in de 
			  constructor.

		del([IP])

			- Deze functie verwijderd een IP adres van de banlijst. Als het IP niet in de banlijst
			  staat, dan gebeurt er niets. Als er geen IP is opgegeven, wordt het IP van de huidige 
			  bezoeker gebruikt.

		flush()

			- Deze functie wist ALLE IP adressen van de banlijst.

		getIp()

			- Deze functie toont het IP adres van de huidige bezoeker. Deze is gelijk aan de 
			  variabele $_SERVER["REMOTE_ADDR"].

		isBlocked([IP])

			- Deze functie kijkt of het opgegeven IP adres in de banlijst aanwezig is. Als er geen 
			  IP is opgegeven, wordt het IP van de huidige bezoeker gebruikt.



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

		VOORBEELD: Controleren of een bezoeker geblokkeerd is.

		include("banlist.cls.php");
		$banlist = new Banlist();

		if($banlist->isBlocked())
		{
			echo "U heeft geen toegang tot deze website.";
			exit;
		}
		else
		{
			echo "Welkom op de website.";
		}

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

		VOORBEELD: Een bezoeker blokkeren

		include("banlist.cls.php");
		$banlist = new Banlist();

		if($banlist->isBlocked())
		{
			echo "U heeft nog steeds geen toegang tot deze website.";
			exit;
		}
		else
		{
			$banlist->add();
			echo "U bent vanaf nu geen toegang meer tot deze website.";
		}

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

		VOORBEELD: Een bezoeker blokkeren als deze een formulier bewust 'fout' invult.

		include("banlist.cls.php");
		$banlist = new Banlist();

		if($banlist->isBlocked())
		{
			echo "U heeft nog steeds geen toegang tot deze website.";
			exit;
		}

		// Uitlezen van formuliervelden
		$naam = str_replace("\"", "\\\"", str_replace("\r", "", str_replace("\n", "", $_POST["naam"])));
		$email = str_replace("\"", "\\\"", str_replace("\r", "", str_replace("\n", "", $_POST["email"])));
		$bericht = $_POST["message"];

		// Note: Het bericht hoeft niet gecontrolleerd te worden, omdat deze niet in de HEADER wordt opgenomen.
		if(preg_match("/cc:|bcc:|to:|from:|content-style:/i", $naam)) // Er wordt gewust gebruik gemaakt van headers
		{
			$banlist->add();
			echo "Hackpoging gedetecteerd.<br />U heeft niet langer toegang tot deze pagina.";
			exit;
		}
		elseif(preg_match("/cc:|bcc:|to:|from:|content-style:/i", $email)) // Er wordt gewust gebruik gemaakt van headers
		{
			$banlist->add();
			echo "Hackpoging gedetecteerd.<br />U heeft niet langer toegang tot deze pagina.";
			exit;
		}

		$to = "info@domain.nl";
		$subject = "Reactie van een bezoeker op www.domain.nl";
		$message = $bericht;
		$headers = "From: \"" . $naam . "\" <" . $email . ">";

		mail($to, $subject, $message, $headers);

	*/

	class Banlist
	{
		var $addresses;
		var $date;
		var $filepath;
		var $ip;

		// Maak een nieuwe banlijst (denk om denk de schrijfrechten van het bestand!!)
		function Banlist($ban_time = 2, $filepath = false)
		{
			$this->addresses = array();
			$this->date = date("YmdHis", mktime(date("H") + $ban_time, date("i"), date("s"), date("m"), date("d"), date("Y"))); // Instellen van de bantijd (default 2 uur)
			$this->filepath = ($filepath ? $filepath : "banlist.csv"); // Instellen van het banlist bestand
			$this->ip = $_SERVER["REMOTE_ADDR"];

			$this->_load();
			$this->_clean();
		}

		// Voeg een IP adres toe aan de banlijst
		// Door een datum toe te voegen wordt het IP t/m deze datum geblokkeerd. Notatie: jaar, maand, dag, uur, minuut, seconde
		// Het script is zo gemaakt dat onvolledige datum worden aangevuld met nullen.
		// Wordt er geen datum opgegeven, dan wordt de huidige datum + time gebruikt om de blokkeertijd te bepalen.
		function add($ip = false, $date = false)
		{
			$ip = ($ip ? $ip : $this->ip);

			if($this->_isIp($ip))
			{
				if($date && is_numeric($date))
				{
					$y = substr($date, 0, 4);
					$m = substr($date, 4, 2);
					$d = substr($date, 6, 2);
					$h = substr($date, 8, 2);
					$i = substr($date, 10, 2);
					$s = substr($date, 12, 2);

					$date = (int) ($y ? $y : "0000") . ($m ? $m : "00") . ($d ? $d : "00") . ($h ? $h : "00") . ($i ? $i : "00") . ($s ? $s : "00");
				}
				else
				{
					$date = $this->date;
				}

				if($date >= date("YmdHis"))
				{
					$this->addresses[$ip] = $date;
					$this->_save();
				}
			}
			else
			{
				echo "Er is geen geldig IP adres opgegeven. IP: " . htmlentities($ip) . "<br />\n";
				echo "FILE: " . __FILE__ . ", LINE: " . __LINE__ . "\n";
				exit;
			}
		}

		// Verwijder een IP adres van de banlijst
		function del($ip = false)
		{
			$ip = ($ip ? $ip : $this->ip);

			if($this->_isIp($ip))
			{
				if($this->addresses[$ip])
				{
					$this->addresses[$ip] = 0;
					$this->_clean();
				}
			}
			else
			{
				echo "Er is geen geldig IP adres opgegeven. IP: " . htmlentities($ip) . "<br />\n";
				echo "FILE: " . __FILE__ . ", LINE: " . __LINE__ . "\n";
				exit;
			}
		}

		// Wis de gehele banlijst
		function flush()
		{
			$this->addresses = array();
			$this->_save();
		}

		function getIp()
		{
			return $this->ip;
		}

		// Kijk of een IP adres is geblokkeerd
		function isBlocked($ip = false)
		{
			$ip = ($ip ? $ip : $this->ip);

			if($this->_isIp($ip))
			{
				if($this->addresses[$ip])
				{
					return true;
				}
			}
			else
			{
				echo "Er is geen geldig IP adres opgegeven. IP: " . htmlentities($ip) . "<br />\n";
				echo "FILE: " . __FILE__ . ", LINE: " . __LINE__ . "\n";
				exit;
			}

			return false;
		}

		// Simpele functie voor het weergeven van de banlijst.
		function toString()
		{
			$str .= "<table border=\"1\">";
			$str .= "<tr>";
			$str .= "<th align=\"left\" valign=\"top\" width=\"150\">IP adres</th>";
			$str .= "<th align=\"left\" valign=\"top\" width=\"150\">Geblokkeerd tot</th>";
			$str .= "</tr>";

			foreach($this->addresses as $key => $value)
			{
				$str .= "<tr>";
				$str .= "<td align=\"left\" valign=\"top\" width=\"150\">" . htmlentities($key) . "</td>";
				$str .= "<td align=\"left\" valign=\"top\" width=\"150\">" . htmlentities($value) . "</td>";
				$str .= "</tr>";
			}

			$str .= "</table>";

			echo $str;
		}


		/*
			Private functions
		*/

		// Verwijder de IP adressen waarvan de ban tijd is overschreden
		function _clean()
		{
			$addresses = array();
			$date = date("YmdHis");

			foreach($this->addresses as $key => $value)
			{
				if($value >= $date)
				{
					$addresses[$key] = $value;
				}
			}

			$this->addresses = $addresses;
			$this->_save();
		}

		// Laad de banlijst file
		function _load()
		{
			if(is_file($this->filepath) === false) // Banlijst bestaat niet
			{
				echo "Er is geen toegang tot het bestand " . htmlentities($this->filepath) . ", dat gebruikt wordt voor het bijhouden van geblokkeerde IP adressen.<br />\n";
				echo "FILE: " . __FILE__ . ", LINE: " . __LINE__ . "<br />\n";
				exit;
			}

			if(is_readable($this->filepath) === false) // Geen leesrechten
			{
				echo "Er zijn geen leesrechten op het bestand " . htmlentities($this->filepath) . ", dat gebruikt wordt voor het bijhouden van geblokkeerde IP adressen.<br />\n";
				echo "FILE: " . __FILE__ . ", LINE: " . __LINE__ . "<br />\n";
				exit;
			}

			if(is_writable($this->filepath) === false) // Geen schrijfrechten
			{
				echo "Er zijn geen schrijfrechten op het bestand " . htmlentities($this->filepath) . ", dat gebruikt wordt voor het bijhouden van geblokkeerde IP adressen.<br />\n";
				echo "FILE: " . __FILE__ . ", LINE: " . __LINE__ . "<br />\n";
				exit;
			}


			// Uitlezen van de banlijst
			if(filesize($this->filepath) > 0)
			{
				$handle = fopen($this->filepath, "r");
				$str = fread($handle, filesize($this->filepath));
				fclose($handle);
			}
			else
			{
				$str = "";
			}

			$addresses = array();

			// Elke regel is een 'ban'
			$lines = explode("\n", $str);

			for($i = 0; $i < sizeof($lines); $i++)
			{
				$values = explode(",", $lines[$i]);

				$ip = trim($values[0]);
				$date = trim($values[1]);

				$addresses[$ip] = $date;
			}

			$this->addresses = $addresses;
		}

		// Opslaan van IP adressen in de banlijst
		function _save()
		{
			$str = "";

			foreach($this->addresses as $key => $value)
			{
				$str .= $key . ", " . $value . "\n";
			}

			// Overschijf de banlijst
			$handle = fopen($this->filepath, "w");
			fwrite($handle, $str);
			fclose($handle);
		}

		function _isIp($value)
		{
			$result = false;

			if($value != "")
			{
				$expr = "/^([0-9]){1,3}([\.]){1,1}([0-9]){1,3}([\.]){1,1}([0-9]){1,3}([\.]){1,1}([0-9]){1,3}$/";
				if(preg_match($expr, $value)) // voldoet aan expressie
				{
					$arr = explode(".", $value);

					if(($arr[0] < 256) && ($arr[1] < 256) && ($arr[2] < 256) && ($arr[3] < 256))
					{
						$result = true;
					}
				}
			}

			return $result;
		}
	}

?>