<?php
// инсталятор базы
if (!isset($ab_version)) die('stop install');

if (!isset($checkdb)) {
$antibot_db = new SQLite3(__DIR__.'/../data/sqlite.db');
} else {
// реинстал базы:
@unlink(__DIR__.'/../data/sqlite2.db');
$antibot_db = new SQLite3(__DIR__.'/../data/sqlite2.db');
}
$antibot_db->busyTimeout(5000);
$antibot_db->exec("PRAGMA journal_mode = WAL;");

/* ipv4 правила:
priority - приоритет (индекс)
search - строка которую добавили, ip или ip/mask (уник)
ip1 - числовое представление стартового ip (индекс)
ip2 - числовое представление конечного ip (индекс)
rule - правило: allow, block, gray, dark
comment - просто коммент, чтоб понятнее было
expires - юникс дата истечения (потом удаляется), если навсегда, то 9999999999
disable - 0 не выключен, 1 правило выключено
*/
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS ipv4rules (
priority INTEGER NOT NULL default '100', 
search TEXT UNIQUE NOT NULL default '', 
ip1 INTEGER NOT NULL default '', 
ip2 INTEGER NOT NULL default '', 
rule TEXT NOT NULL default '', 
comment TEXT NOT NULL default '', 
expires INTEGER NOT NULL default '9999999999', 
disable INTEGER NOT NULL default '0'
);");
// индексы:
$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS priority4 ON ipv4rules (priority);"); 
$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS ipv4index1 ON ipv4rules (ip1);"); 
$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS ipv4index2 ON ipv4rules (ip2);"); 

if (!isset($checkdb)) {
// дефолтные ip сервера:
$add = @$antibot_db->exec("INSERT INTO ipv4rules (priority, search, ip1, ip2, rule, comment, expires) VALUES ('10', '127.0.0.1', '".AbIp2num('127.0.0.1')."', '".AbIp2num('127.0.0.1')."', 'allow', 'Local IP', '9999999999');");

if (filter_var($_SERVER['SERVER_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
$add = @$antibot_db->exec("INSERT INTO ipv4rules (priority, search, ip1, ip2, rule, comment, expires) VALUES ('10', '".$_SERVER['SERVER_ADDR']."', '".AbIp2num($_SERVER['SERVER_ADDR'])."', '".AbIp2num($_SERVER['SERVER_ADDR'])."', 'allow', 'Local IP from SERVER_ADDR', '9999999999');");
}

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://antibot.cloud/static/ip.php');
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, 600);
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_USERAGENT, 'AntiBot');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
curl_setopt($ch, CURLOPT_FTP_SSL, CURLFTPSSL_TRY);
$serverip = @trim(strip_tags(curl_exec($ch)));
curl_close($ch);

if (filter_var($serverip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
$add = @$antibot_db->exec("INSERT INTO ipv4rules (priority, search, ip1, ip2, rule, comment, expires) VALUES ('10', '".$serverip."', '".AbIp2num($serverip)."', '".AbIp2num($serverip)."', 'allow', 'Server IP', '9999999999');");
}
}

/* ipv6 правила:
priority - приоритет (индекс)
search - строка которую добавили, ip или ip/mask (уник)
ip1 - числовое представление стартового ip (индекс)
ip2 - числовое представление конечного ip (индекс)
rule - правило: allow, block, gray, dark
comment - просто коммент, чтоб понятнее было
expires - юникс дата истечения (потом удаляется), если навсегда, то 9999999999
disable - 0 не выключен, 1 правило выключено
*/
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS ipv6rules (
priority INTEGER NOT NULL default '100', 
search TEXT UNIQUE NOT NULL default '', 
ip1 INTEGER NOT NULL default '', 
ip2 INTEGER NOT NULL default '', 
rule TEXT NOT NULL default '', 
comment TEXT NOT NULL default '', 
expires INTEGER NOT NULL default '9999999999', 
disable INTEGER NOT NULL default '0'
);");
// индексы:
$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS priority6 ON ipv6rules (priority);"); 
$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS ipv6index1 ON ipv6rules (ip1);"); 
$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS ipv6index2 ON ipv6rules (ip2);"); 

/*
rules - все прочие правила:
* 
priority - приоритет (индекс)
type - тип данных: useragent, country, lang (2 зн код), referer (хост), ptr, asname, asnum, uri, scriptname, httpaccept
data - значение (может быть пустым)
search - строка которую ищем по точному совпадению (уник) вида: referer=iframe-toloka.com (индекс)
rule - правило: allow, block, gray, dark
comment - просто коммент, чтоб понятнее было
expires - юникс дата истечения (потом удаляется), если навсегда, то 9999999999
disable - 0 не выключен, 1 правило выключено
*/
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS rules (
priority INTEGER NOT NULL default '1', 
type TEXT NOT NULL default '', 
data TEXT NOT NULL default '', 
search TEXT UNIQUE NOT NULL default '', 
rule TEXT NOT NULL default '', 
comment TEXT NOT NULL default '', 
expires INTEGER NOT NULL default '9999999999', 
disable INTEGER NOT NULL default '0'
);");

$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS i_priority ON rules (priority);"); 
$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS i_search ON rules (search);");

if (!isset($checkdb)) {
$add = @$antibot_db->exec("INSERT INTO rules (priority, type, data, search, rule, comment) VALUES ('10', 'useragent', '', 'useragent=', 'block', 'Empty User-Agent');");
$add = @$antibot_db->exec("INSERT INTO rules (priority, type, data, search, rule, comment) VALUES ('10', 'lang', '', 'lang=', 'block', 'Empty Language');");
$add = @$antibot_db->exec("INSERT INTO rules (priority, type, data, search, rule, comment) VALUES ('10', 'referer', '', 'referer=', 'gray', 'Empty Referer');");
}

// ---------------------------------------------------------------------

// основной лог, таблица hits:
/*
cid - id клика, из микротайм, уник, PRIMARY KEY, вида 16318017019918
date - unix дата
ip - полный адрес 127.0.0.1 + индекс по этому полю
ptr - userhost.com. (для заглушки из пхп)
useragent - полностью
uid - хэш из cookie, хэг от ипа и юзерагента, для слежения за юзером
country - страна (код страны типа: RU)
referer - реферер полностью
page - текущая страница полностью
lang - язык полностью
generation - время генерации скрипта антибота
passed - INTEGER + индекс по этому полю
* получил заглушку и остался на ней (0 - STOP)
* прошел проверку автоматически в облаке или ab.php (1 - AUTO)
* прошел кликом (2 - CLICK)
* если это хит мимо заглушки имеющих куки (3 - LOCAL)
* если прошли по разрешающему правилу (4 - ALLOW)
* белый бот (по ip и из конфига) (5 - GOODIP)
* заблокированные по правилам или из конфига (6 - BLOCK)
* фейк боты (маскирующиеся белыми ботами) (7 - FAKE)
* кликнули с ошибкой (8 - MISS)
recaptcha - рейтинг score, 
js_w - ширина монитора (из JS)
js_h - высота монитора (из JS)
js_cw - ширина окна браузера (из JS)
js_ch - высота окна браузера (из JS)
js_co - colordepth (из JS)
js_pi - pixeldepth (из JS)
refhost - хост реферера
adblock - включен блокировщик рекламы (1) или нет (0)  (из JS)
asnum - номер блока ip провайдера
asname - название провайдера
result - причина блокировки из облака (из JS) или слово GRAY
http_accept - типа text/html,application/xhtml+xml,application/xml;q=0.9
method - GET, POST, PUT, HEAD, DELETE, TRACE, OPTIONS, CONNECT
ym_uid - ClientID яндекс метрики, из cookie $_COOKIE['_ym_uid'] вида: 1620997730486452159 (число)
ga_uid - идентификатор клиента в Google Analytics из cookie $_COOKIE['_ga'] вида "GA1.2.1709431122.1631721710"
ip_short - укороченный ipv4/24 или ipv6/64
*/
// основная таблица, добавить параметр UNINDEXED к ненужным полям по которым нету поиска:
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS hits (
cid TEXT NOT NULL PRIMARY KEY default '', 
date INTEGER NOT NULL default '', 
ip TEXT NOT NULL default '', 
ptr TEXT NOT NULL default '', 
useragent TEXT NOT NULL default '', 
uid TEXT NOT NULL default '', 
country TEXT NOT NULL default '', 
referer TEXT NOT NULL default '', 
page TEXT NOT NULL default '', 
lang TEXT NOT NULL default '', 
generation TEXT NOT NULL default '', 
passed INTEGER NOT NULL default '0', 
recaptcha TEXT NOT NULL default '0', 
js_w INTEGER NOT NULL default '', 
js_h INTEGER NOT NULL default '', 
js_cw INTEGER NOT NULL default '', 
js_ch INTEGER NOT NULL default '', 
js_co INTEGER NOT NULL default '', 
js_pi INTEGER NOT NULL default '', 
refhost TEXT NOT NULL default '', 
adblock INTEGER NOT NULL default '', 
asnum TEXT NOT NULL default '', 
asname TEXT NOT NULL default '', 
result TEXT NOT NULL default '', 
http_accept TEXT NOT NULL default '', 
method TEXT NOT NULL default '', 
ym_uid TEXT NOT NULL default '', 
ga_uid TEXT NOT NULL default '', 
ip_short TEXT NOT NULL default ''
);");

$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS i_ip ON hits (ip);"); 
$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS i_passed ON hits (passed);"); 
$index = $antibot_db->exec("CREATE INDEX IF NOT EXISTS i_date ON hits (date);"); 

/*
таблица счетчиков (в некотором роде кеш) по датам:
обновлять кроном
* 
date - дата вида 20191223
test - колво попавших на заглушку
auto - колво автоматически прошедших заглушку
click - колво успешно кликнувших на кнопку
miss - колво ошибочно кликнувших
allow - колво прошедших по общим белым правилам
goodip - колво белых ботов из конфига и по базе белых ip
local - колво прошедших имеющих cookie
uusers - колво уников (подсчет по ip: AUTO CLICK ALLOW LOCAL)
husers - колво хитов (подсчет по ip: AUTO CLICK ALLOW LOCAL)
block - колво хитов забаненных (страна, язык, реферер, ptr)
fakes - колво хитов фейк ботов
google - кол-во хитов гугл бота
yandex - кол-во хитов яндекс бота
bing - кол-во хитов бинг бота
*/
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS counters (
date INTEGER UNIQUE NOT NULL default '', 
test INTEGER NOT NULL default '0', 
auto INTEGER NOT NULL default '0', 
click INTEGER NOT NULL default '0', 
miss INTEGER NOT NULL default '0', 
allow INTEGER NOT NULL default '0', 
goodip INTEGER NOT NULL default '0', 
local INTEGER NOT NULL default '0', 
uusers INTEGER NOT NULL default '0', 
husers INTEGER NOT NULL default '0', 
block INTEGER NOT NULL default '0', 
fakes INTEGER NOT NULL default '0', 
google INTEGER NOT NULL default '0', 
yandex INTEGER NOT NULL default '0', 
bing INTEGER NOT NULL default '0'
);");

/*
priority - приоритет
search - часть юзерагента
data - список валидных ptr
rule - правило: allow, block, gray, dark
comment - просто коммент, чтоб понятнее было
disable - 0 не выключен, 1 правило выключено
* 
в php файл сохранять кэш в 2 массива ab_se как было в конфиге и массив ab_rule в котором search и rule
*/
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS ab_se (
priority INTEGER NOT NULL default '100', 
search TEXT UNIQUE NOT NULL default '', 
data TEXT NOT NULL default '', 
rule TEXT NOT NULL default '', 
comment TEXT NOT NULL default '', 
disable INTEGER NOT NULL default '0'
);");

if (!isset($checkdb)) {
// дефолтные поисковики:
$add = @$antibot_db->exec("INSERT INTO ab_se (priority, search, data, rule, comment) VALUES ('10', 'Googlebot', '.googlebot.com', 'allow', 'GoogleBot main indexer');");
$add = @$antibot_db->exec("INSERT INTO ab_se (priority, search, data, rule, comment) VALUES ('10', 'yandex.com', '.yandex.ru .yandex.net .yandex.com', 'allow', 'All Yandex bots');");
$add = @$antibot_db->exec("INSERT INTO ab_se (priority, search, data, rule, comment) VALUES ('10', 'Mail.RU_Bot', '.mail.ru .smailru.net', 'allow', 'All Bots Mail.RU Indexers');");
$add = @$antibot_db->exec("INSERT INTO ab_se (priority, search, data, rule, comment) VALUES ('10', 'bingbot', 'search.msn.com', 'allow', 'Bing.com indexer');");
$add = @$antibot_db->exec("INSERT INTO ab_se (priority, search, data, rule, comment) VALUES ('10', 'msnbot', 'search.msn.com', 'allow', 'Additional Indexer Bing.com');");
$add = @$antibot_db->exec("INSERT INTO ab_se (priority, search, data, rule, comment) VALUES ('10', 'Google-Site-Verification', '.googlebot.com .google.com', 'allow', 'Check for Google Search Console');");

$se_save = '<?php
$ab_rule[\'Googlebot\'] = \'allow\';
$ab_se[\'Googlebot\'] = array(\'.googlebot.com\');
$ab_rule[\'yandex.com\'] = \'allow\';
$ab_se[\'yandex.com\'] = array(\'.yandex.ru\', \'.yandex.net\', \'.yandex.com\');
$ab_rule[\'Mail.RU_Bot\'] = \'allow\';
$ab_se[\'Mail.RU_Bot\'] = array(\'.mail.ru\', \'.smailru.net\');
$ab_rule[\'bingbot\'] = \'allow\';
$ab_se[\'bingbot\'] = array(\'search.msn.com\');
$ab_rule[\'msnbot\'] = \'allow\';
$ab_se[\'msnbot\'] = array(\'search.msn.com\');
$ab_rule[\'Google-Site-Verification\'] = \'allow\';
$ab_se[\'Google-Site-Verification\'] = array(\'.googlebot.com\', \'.google.com\');
';
file_put_contents(__DIR__.'/../data/se.php', $se_save, LOCK_EX);
}

/*
priority - приоритет
search - часть урла вида /wp-content/uploads/
rule - правило: allow, block, gray, dark
comment - просто коммент, чтоб понятнее было
disable - 0 не выключен, 1 правило выключено
* 
в php файл сохранять кэш массива ab_path в котором search и rule
*/
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS ab_path (
priority INTEGER NOT NULL default '100', 
search TEXT UNIQUE NOT NULL default '', 
rule TEXT NOT NULL default '', 
comment TEXT NOT NULL default '',
disable INTEGER NOT NULL default '0'
);");

if (!isset($checkdb)) {
file_put_contents(__DIR__.'/../data/path.php', '<?php'."\n", LOCK_EX);

// это вордпресс:
if (file_exists(__DIR__.'/../../wp-config.php')) {
$add = @$antibot_db->exec("INSERT INTO ab_path (priority, search, rule, comment, disable) VALUES ('10', '/wp-cron.php', 'allow', 'for WordPress', '0');");
$add = @$antibot_db->exec("INSERT INTO ab_path (priority, search, rule, comment, disable) VALUES ('10', '/wp-admin/admin-ajax.php', 'allow', 'for WordPress', '0');");
$add = @$antibot_db->exec("INSERT INTO ab_path (priority, search, rule, comment, disable) VALUES ('10', '/wp-admin/post.php', 'allow', 'for WordPress', '0');");
$for_wp = '<?php
$ab_path[\'/wp-cron.php\'] = \'allow\';
$ab_path[\'/wp-admin/admin-ajax.php\'] = \'allow\';
$ab_path[\'/wp-admin/post.php\'] = \'allow\';
';
if (is_dir(__DIR__.'/../../wp-content/plugins/woocommerce')) {
$add = @$antibot_db->exec("INSERT INTO ab_path (priority, search, rule, comment, disable) VALUES ('10', '/?wc-ajax=', 'allow', 'for WooCommerce', '0');");
$for_wp .= '$ab_path[\'/?wc-ajax=\'] = \'allow\';
';
}
file_put_contents(__DIR__.'/../data/path.php', $for_wp, LOCK_EX);
}
}

/*
k - 127.0.0.0/24
v - HTTP_X_REAL_IP
*/
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS ab_proxy (
k TEXT UNIQUE NOT NULL default '', 
v TEXT NOT NULL default ''
);");

if (!isset($checkdb)) {
file_put_contents(__DIR__.'/../data/proxy.php', '<?php'."\n", LOCK_EX);
}

/* лог авторизаций:
date - юникс дата
ip - 
country - код страны
result - 1 успешная авторизация, 0 ошибка авторизации
*/
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS auth_log (
date INTEGER NOT NULL default '', 
ip TEXT NOT NULL default '', 
country TEXT NOT NULL default '', 
result TEXT NOT NULL default ''
);");

/* база кэша ptr:
ip - v4 или v6
ptr значение
date - дата в юникс
etime - время выполнения функции получения ptr
*/
$query = $antibot_db->exec("CREATE TABLE IF NOT EXISTS ptrcache (
ip TEXT UNIQUE NOT NULL default '', 
ptr TEXT NOT NULL default '', 
date INTEGER NOT NULL default '0', 
etime INTEGER NOT NULL default '0'
);");

if (!isset($checkdb)) {
echo 'The database is installed.
<script>location.reload();</script>';
}
