<?php

class BotDefender
{
    private $key;
    private $strictness;
    private $user_agent;
    private $failure_redirect;
    private $success_redirect;
    private $max_fraudscore;
    private $allow_crawler;
    private $rules;

    private $debug = false;
    private $logFile = 'bot_defender_log.txt';

    const BASE_API_URL = 'https://www.ipqualityscore.com/api/json/ip/%s/%s';

    public function __construct($key)
    {
        $this->key = $key;
        $this->strictness = 0;
        $this->user_agent = false;
        $this->failure_redirect = null;
        $this->success_redirect = null;
        $this->max_fraudscore = null;
        $this->allow_crawler = null;
        $this->rules = null;
    }

    public function setDebug($value)
    {
        $this->debug = $value;
    }

    public function setStrictness($value)
    {
        $this->strictness = $value;
    }

    public function passUserAgent($value)
    {
        $this->user_agent = $value;
    }

    public function setFailureRedirect($value)
    {
        $this->failure_redirect = $value;
    }

    public function setSuccessRedirect($value)
    {
        $this->success_redirect = $value;
    }

    public function setMaxFraudscore($value)
    {
        $this->max_fraudscore = $value;
    }

    public function setAllowCrawler($value)
    {
        $this->allow_crawler = $value;
    }

    public function setRules($value)
    {
        $this->rules = $value;
    }

    public function checkIP($ip)
    {
        $curl = curl_init();
        $url = sprintf(self::BASE_API_URL, $this->key, urlencode($ip));
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);

        $parameters = array('strictness' => $this->strictness);
        if ($this->user_agent && isset($_SERVER['HTTP_USER_AGENT'])) {
            $parameters['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
        }

        curl_setopt($curl, CURLOPT_POSTFIELDS, $parameters);
        $result = curl_exec($curl);

        if ($result === false) {
            $this->log("cURL Error: " . curl_error($curl));
        } else {
            $this->log("API Response: " . $result);
        }

        $data = json_decode($result, true);
        curl_close($curl);

        return $data;
    }

    public function forceRedirect($type = 'proxy')
    {
        $ip = $this->getIP();
        $this->log("Checking IP: " . $ip);

        $result = $this->checkIP($ip);

        if (!is_array($result) || empty($result)) {
            $this->log("API check failed or returned unexpected result");
            return;
        }

        $this->log("API Result: " . print_r($result, true));

        if (isset($result['is_crawler'])) {
            if ($this->allow_crawler === true && $result['is_crawler'] === true) {
                $this->log("Crawler allowed");
                return true;
            }
        }

        if ($this->max_fraudscore !== null) {
            if (isset($result['fraud_score']) && $result['fraud_score'] > $this->max_fraudscore) {
                $this->log("Fraud score exceeded: " . $result['fraud_score']);
                exit;
            }
        }

        if ($this->rules !== null && is_array($this->rules)) {
            foreach ($this->rules as $rule) {
                if (isset($rule['comparator']) && isset($rule['fraudscore']) && isset($rule['url'])) {
                    if (!empty($rule['comparator']) && !empty($rule['fraudscore']) && !empty($rule['url'])) {
                        $userScore = $result['fraud_score'];
                        $ruleScore = intval($rule['fraudscore']);
                        $comparator = intval($rule['comparator']);
                        $url = $rule['url'];
                        switch ($comparator) {
                            case 1:
                                $this->redirect($url, $userScore === $ruleScore);
                                break;
                            case 2:
                                $this->redirect($url, $userScore > $ruleScore);
                                break;
                            case 3:
                                $this->redirect($url, $userScore < $ruleScore);
                                break;
                            case 4:
                                $this->redirect($url, $userScore !== $ruleScore);
                                break;
                            case 5:
                                $this->redirect($url, $userScore >= $ruleScore);
                                break;
                            case 6:
                                $this->redirect($url, $userScore <= $ruleScore);
                                break;
                        }
                    }
                }
            }
        }

        if (isset($result[$type])) {
            if ($result[$type] === true) {
                $this->log("$type detected, redirecting to failure URL");
                if ($this->failure_redirect !== null) {
                    $this->redirect($this->failure_redirect);
                } else {
                    exit;
                }
            } else {
                $this->log("$type not detected, proceeding normally");
                if ($this->success_redirect !== null) {
                    $this->redirect($this->success_redirect);
                }
            }
        } else {
            $this->log("$type not found in result");
        }
    }

    private function redirect($url, $redirect = true)
    {
        if ($redirect === true) {
            exit(header(sprintf("Location: %s", $url)));
        }
        return false;
    }

    private function getIP()
    {
        return (isset($_SERVER["HTTP_CF_CONNECTING_IP"]) ? $_SERVER["HTTP_CF_CONNECTING_IP"] : $_SERVER["REMOTE_ADDR"]);
    }

    public function performAdditionalChecks()
    {
        $bannedIPs = $this->getBannedIPs();
        $bannedUserAgents = $this->getBannedUserAgents();
        $bannedWords = $this->getBannedWords();

        $ip = $this->getIP();
        $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower($_SERVER['HTTP_USER_AGENT']) : '';
        $hostname = gethostbyaddr($ip);

        foreach ($bannedIPs as $bannedIP) {
            if (preg_match('/' . $bannedIP . '/', $ip)) {
                $this->blockAccess();
            }
        }

        foreach ($bannedUserAgents as $bannedUA) {
            if (strpos($userAgent, strtolower($bannedUA)) !== false) {
                $this->blockAccess();
            }
        }

        foreach ($bannedWords as $word) {
            if (substr_count($hostname, $word) > 0) {
                $this->blockAccess();
            }
        }
    }

    private function blockAccess()
    {
        header("HTTP/1.0 403 Forbidden");
        exit("<h1>403 Forbidden</h1><p>Access Denied.</p>");
    }

    private function log($message)
    {
        $logMessage = date('Y-m-d H:i:s') . ' - ' . $message . PHP_EOL;
        file_put_contents($this->logFile, $logMessage, FILE_APPEND);
        if ($this->debug) {
            echo $logMessage . "<br>";
        }
    }

    private function getBannedIPs()
    {
        // Add your complete list of banned IP patterns here
        return [
            "^66.102.*.*",
            "^38.100.*.*",
            "^107.170.*.*",
            "^149.20.*.*",
            "^38.105.*.*",
            "^74.125.*.*",
            "^66.150.14.*",
            "^54.176.*.*",
            "^38.100.*.*",
            "^184.173.*.*",
            "^66.249.*.*",
            "^128.242.*.*",
            "^72.14.192.*",
            "^208.65.144.*",
            "^74.125.*.*",
            "^209.85.128.*",
            "^216.239.32.*",
            "^74.125.*.*",
            "^207.126.144.*",
            "^173.194.*.*",
            "^64.233.160.*",
            "^72.14.192.*",
            "^66.102.*.*",
            "^64.18.*.*",
            "^194.52.68.*",
            "^194.72.238.*",
            "^62.116.207.*",
            "^212.50.193.*",
            "^69.65.*.*",
            "^50.7.*.*",
            "^131.212.*.*",
            "^46.116.*.*",
            "^62.90.*.*",
            "^89.138.*.*",
            "^207.*.*.*",
            "^207.*.*.*",
            "^82.166.*.*",
            "^85.64.*.*",
            "^85.250.*.*",
            "^89.138.*.*",
            "^93.172.*.*",
            "^109.186.*.*",
            "^194.90.*.*",
            "^212.29.192.*",
            "^212.29.224.*",
            "^212.143.*.*",
            "^212.150.*.*",
            "^212.235.*.*",
            "^217.132.*.*",
            "^50.97.*.*",
            "^217.132.*.*",
            "^209.85.*.*",
            "^66.205.64.*",
            "^204.14.48.*",
            "^64.27.2.*",
            "^67.15.*.*",
            "^202.108.252.*",
            "^193.47.80.*",
            "^64.62.136.*",
            "^66.221.*.*",
            "^64.62.175.*",
            "^198.54.*.*",
            "^192.115.134.*",
            "^216.252.167.*",
            "^193.253.199.*",
            "^69.61.12.*",
            "^64.37.103.*",
            "^38.144.36.*",
            "^64.124.14.*",
            "^206.28.72.*",
            "^209.73.228.*",
            "^158.108.*.*",
            "^168.188.*.*",
            "^66.207.120.*",
            "^167.24.*.*",
            "^192.118.48.*",
            "^67.209.128.*",
            "^12.148.209.*",
            "^12.148.196.*",
            "^193.220.178.*",
            "68.65.53.71",
            "^198.25.*.*",
            "^64.106.213.*",
        ];
    }

    private function getBannedUserAgents()
    {
        // Add your complete list of banned user agent keywords here
        return [
            "googlebot",
            "yahoo",
            "slurp",
            "yahooSeeker",
            "facebookexternalhit",
            "ia_archiver",
            "yandexbot",
            "baiduspider",
            "crawler",
            "httrack",
            "pycurl",
            "python-requests",
            "curl",
            "wget",
            "phish",
            "Http Crawler",
        ];
    }

    private function getBannedWords()
    {
        // Add your complete list of banned words here
        return [
            "bot",
            "above",
            "google",
            "softlayer",
            "amazonaws",
            "cyveillance",
            "compatible",
            "facebook",
            "phishtank",
            "mozilla",
            "dreamhost",
            "netpilot",
            "calyxinstitute",
            "tor-exit",
            "apache-httpclient",
            "lssrocketcrawler",
            "Trident",
            "X11",
            "Macintosh",
            "crawler",
            "urlredirectresolver",
            "jetbrains",
            "spam",
            "windows 95",
            "Windows XP",
            "windows xp",
            "windows 98",
            "acunetix",
            "netsparker",
            "google",
            "007ac9",
            "008",
            "192.comagent",
            "200pleasebot",
            "360spider",
            "4seohuntbot",
            "50.nu",
            "a6-indexer",
            "admantx",
            "amznkassocbot",
            "aboundexbot",
            "aboutusbot",
            "abrave spider",
            "accelobot",
            "acoonbot",
            "addthis.com",
            "adsbot-google",
            "ahrefsbot",
            "alexabot",
            "amagit.com",
            "analytics",
            "antbot",
            "apercite",
            "aportworm",
            'Googlebot',
            'Baiduspider',
            'ia_archiver',
            'R6_FeedFetcher',
            'NetcraftSurveyAgent',
            'Sogou web spider',
            'bingbot',
            'Yahoo! Slurp',
            'facebookexternalhit',
            'PrintfulBot',
            'msnbot',
            'Twitterbot',
            'UnwindFetchor',
            'urlresolver',
            'Butterfly',
            'TweetmemeBot',
            'PaperLiBot',
            'MJ12bot',
            'AhrefsBot',
            'Exabot',
            'Ezooms',
            'YandexBot',
            'SearchmetricsBot',
            'picsearch',
            'TweetedTimes Bot',
            'QuerySeekerSpider',
            'ShowyouBot',
            'woriobot',
            'merlinkbot',
            'BazQuxBot',
            'Kraken',
            'SISTRIX Crawler',
            'R6_CommentReader',
            'magpie-crawler',
            'GrapeshotCrawler',
            'PercolateCrawler',
            'MaxPointCrawler',
            'R6_FeedFetcher',
            'NetSeer crawler',
            'grokkit-crawler',
            'SMXCrawler',
            'PulseCrawler',
            'Y!J-BRW',
            '80legs.com/webcrawler',
            'Mediapartners-Google',
            'Spinn3r',
            'InAGist',
            'Python-urllib',
            'NING',
            'TencentTraveler',
            'Feedfetcher-Google',
            'mon.itor.us',
            'spbot',
            'Feedly',
            'bot',
            'curl',
            'spider',
            'crawler',
            "abot",
            "dbot",
            "ebot",
            "hbot",
            "kbot",
            "lbot",
            "mbot",
            "nbot",
            "obot",
            "pbot",
            "rbot",
            "sbot",
            "tbot",
            "vbot",
            "ybot",
            "zbot",
            "bot.",
            "bot/",
            "_bot",
            ".bot",
            "/bot",
            "-bot",
            ":bot",
            "(bot",
            "crawl",
            "slurp",
            "spider",
            "seek",
            "accoona",
            "acoon",
            "adressendeutschland",
            "ah-ha.com",
            "ahoy",
            "altavista",
            "ananzi",
            "anthill",
            "appie",
            "arachnophilia",
            "arale",
            "araneo",
            "aranha",
            "architext",
            "aretha",
            "arks",
            "asterias",
            "atlocal",
            "atn",
            "atomz",
            "augurfind",
            "backrub",
            "bannana_bot",
            "baypup",
            "bdfetch",
            "big brother",
            "biglotron",
            "bjaaland",
            "blackwidow",
            "blaiz",
            "blog",
            "blo.",
            "bloodhound",
            "boitho",
            "booch",
            "bradley",
            "butterfly",
            "calif",
            "cassandra",
            "ccubee",
            "cfetch",
            "charlotte",
            "churl",
            "cienciaficcion",
            "cmc",
            "collective",
            "comagent",
            "combine",
            "computingsite",
            "csci",
            "curl",
            "cusco",
            "daumoa",
            "deepindex",
            "delorie",
            "depspid",
            "deweb",
            "echo blinde kuh",
            "digger",
            "ditto",
            "dmoz",
            "docomo",
            "download express",
            "dtaagent",
            "dwcp",
            "ebiness",
            "ebingbong",
            "e-collector",
            "ejupiter",
            "emacs-w3 search engine",
            "esther",
            "evliya celebi",
            "ezresult",
            "falcon",
            "felix ide",
            "ferret",
            "fetchrover",
            "fido",
            "findlinks",
            "fireball",
            "fish search",
            "fouineur",
            "funnelweb",
            "gazz",
            "gcreep",
            "genieknows",
            "getterroboplus",
            "geturl",
            "glx",
            "goforit",
            "golem",
            "grabber",
            "grapnel",
            "gralon",
            "griffon",
            "gromit",
            "grub",
            "gulliver",
            "hamahakki",
            "harvest",
            "havindex",
            "helix",
            "heritrix",
            "hku www octopus",
            "homerweb",
            "htdig",
            "html index",
            "html_analyzer",
            "htmlgobble",
            "hubater",
            "hyper-decontextualizer",
            "ia_archiver",
            "ibm_planetwide",
            "ichiro",
            "iconsurf",
            "iltrovatore",
            "image.kapsi.net",
            "imagelock",
            "incywincy",
            "indexer",
            "infobee",
            "informant",
            "ingrid",
            "inktomisearch.com",
            "inspector web",
            "intelliagent",
            "internet shinchakubin",
            "ip3000",
            "iron33",
            "israeli-search",
            "ivia",
            "jack",
            "jakarta",
            "javabee",
            "jetbot",
            "jumpstation",
            "katipo",
            "kdd-explorer",
            "kilroy",
            "knowledge",
            "kototoi",
            "kretrieve",
            "labelgrabber",
            "lachesis",
            "larbin",
            "legs",
            "libwww",
            "linkalarm",
            "link validator",
            "linkscan",
            "lockon",
            "lwp",
            "lycos",
            "magpie",
            "mantraagent",
            "mapoftheinternet",
            "marvin/",
            "mattie",
            "mediafox",
            "mediapartners",
            "mercator",
            "merzscope",
            "microsoft url control",
            "minirank",
            "miva",
            "mj12",
            "mnogosearch",
            "moget",
            "monster",
            "moose",
            "motor",
            "multitext",
            "muncher",
            "muscatferret",
            "mwd.search",
            "myweb",
            "najdi",
            "nameprotect",
            "nationaldirectory",
            "nazilla",
            "ncsa beta",
            "nec-meshexplorer",
            "nederland.zoek",
            "netcarta webmap engine",
            "netmechanic",
            "netresearchserver",
            "netscoop",
            "newscan-online",
            "nhse",
            "nokia6682/",
            "nomad",
            "noyona",
            "nutch",
            "nzexplorer",
            "objectssearch",
            "occam",
            "omni",
            "open text",
            "openfind",
            "openintelligencedata",
            "orb search",
            "osis-project",
            "pack rat",
            "pageboy",
            "pagebull",
            "page_verifier",
            "panscient",
            "parasite",
            "partnersite",
            "patric",
            "pear.",
            "pegasus",
            "peregrinator",
            "pgp key agent",
            "phantom",
            "phpdig",
            "picosearch",
            "piltdownman",
            "pimptrain",
            "pinpoint",
            "pioneer",
            "piranha",
            "plumtreewebaccessor",
            "pogodak",
            "poirot",
            "pompos",
            "poppelsdorf",
            "poppi",
            "popular iconoclast",
            "psycheclone",
            "publisher",
            "python",
            "rambler",
            "raven search",
            "roach",
            "road runner",
            "roadhouse",
            "robbie",
            "robofox",
            "robozilla",
            "rules",
            "salty",
            "sbider",
            "scooter",
            "scoutjet",
            "scrubby",
            "search.",
            "searchprocess",
            "semanticdiscovery",
            "senrigan",
            "sg-scout",
            "shai'hulud",
            "shark",
            "shopwiki",
            "sidewinder",
            "sift",
            "silk",
            "simmany",
            "site searcher",
            "site valet",
            "sitetech-rover",
            "skymob.com",
            "sleek",
            "smartwit",
            "sna-",
            "snappy",
            "snooper",
            "sohu",
            "speedfind",
            "sphere",
            "sphider",
            "spinner",
            "spyder",
            "steeler/",
            "suke",
            "suntek",
            "supersnooper",
            "surfnomore",
            "sven",
            "sygol",
            "szukacz",
            "tach black widow",
            "tarantula",
            "templeton",
            "/teoma",
            "t-h-u-n-d-e-r-s-t-o-n-e",
            "theophrastus",
            "titan",
            "titin",
            "tkwww",
            "toutatis",
            "t-rex",
            "tutorgig",
            "twiceler",
            "twisted",
            "ucsd",
            "udmsearch",
            "url check",
            "updated",
            "vagabondo",
            "valkyrie",
            "verticrawl",
            "victoria",
            "vision-search",
            "volcano",
            "voyager/",
            "voyager-hc",
            "w3c_validator",
            "w3m2",
            "w3mir",
            "walker",
            "wallpaper",
            "wanderer",
            "wauuu",
            "wavefire",
            "web core",
            "web hopper",
            "web wombat",
            "webbandit",
            "webcatcher",
            "webcopy",
            "webfoot",
            "weblayers",
            "weblinker",
            "weblog monitor",
            "webmirror",
            "webmonkey",
            "webquest",
            "webreaper",
            "websitepulse",
            "websnarf",
            "webstolperer",
            "webvac",
            "webwalk",
            "webwatch",
            "webwombat",
            "webzinger",
            "wget",
            "whizbang",
            "whowhere",
            "wild ferret",
            "worldlight",
            "wwwc",
            "wwwster",
            "xenu",
            "xget",
            "xift",
            "xirq",
            "yandex",
            "yanga",
            "yeti",
            "yodao",
            "zao/",
            "zippp",
            "zyborg",
        ];
    }
}
