parent
ef348f1979
commit
a7ea9227cf
@ -0,0 +1,6 @@ |
||||
PHP/KStats.Secrets.php |
||||
KStats.apache2.conf |
||||
Public/index.html |
||||
Public/es |
||||
Public/dev |
||||
Data |
@ -0,0 +1,183 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="es" dir="ltr"> |
||||
<head> |
||||
<title>{title}</title> |
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> |
||||
<meta charset="utf-8" /> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" /> |
||||
<link rel="icon" href="/images/KStats-32.png" sizes="32x32" /> |
||||
<link rel="icon" href="/images/KStats-192.png" sizes="192x192" /> |
||||
<link rel="icon" href="/images/KStats-512.png" sizes="512x512" /> |
||||
<link rel="apple-touch-icon-precomposed" href="/images/KStats-180.png" /> |
||||
<meta name="msapplication-TileImage" content="/images/KStats-270.png" /> |
||||
|
||||
<meta name="licence:text" content="© 2020-2021 CopyLeft. GPLv3" /> |
||||
<meta name="licence:link" content="https://www.gnu.org/licenses/gpl-3.0.txt" /> |
||||
<meta name="licence:icon" content="https://www.gnu.org/graphics/gplv3-88x31.png" /> |
||||
|
||||
<meta name="xdoc:link" content="{url}" /> |
||||
<meta name="xdoc:author" content="{author}" /> |
||||
<meta name="xdoc:since" content="{since}" /> |
||||
<meta name="xdoc:version" content="{version}" /> |
||||
<meta name="xdoc:access" content="public" /> |
||||
|
||||
<meta name="description" data-i18n="kstats_description" content="{description}" /> |
||||
<meta name="keywords" data-i18n="kstats_keywords" content="{key_words}" /> |
||||
<meta name="author" content="{author}" /> |
||||
<meta name="copyright" content="© 2020-2021 CopyLeft" /> |
||||
<meta name="robots" content="index,follow" /> |
||||
<meta name="googlebot" content="index,follow,max-snippet:-1,max-image-preview:large,max-video-preview:-1" /> |
||||
<meta name="bingbot" content="index,follow,max-snippet:-1,max-image-preview:large,max-video-preview:-1" /> |
||||
<!--<meta http-equiv="refresh" content="30" />--> |
||||
<!--<meta http-equiv="cache-control" content="no-cache" />--> |
||||
<!--<meta http-equiv="expires" content="0" />--> |
||||
<link rel="canonical" href="{url}" /> |
||||
<link rel="alternate" href="{url}" hreflang="es" /> |
||||
<meta property="og:locale:alternate" content="es_ES" /> |
||||
<meta name="referrer" content="origin" /> |
||||
<meta name="fragment" content="!" /><!-- Para uso AJAX --> |
||||
<meta name="language" content="es" /> |
||||
<meta name="revisit-after" content="7 days" /><!-- Regreso de las arañas. Información Crawl. --> |
||||
<meta name="rating" content="general" /><!-- Tipo de contenido: general, mature, restricted, adult, 14 years, safe for kids. --> |
||||
<meta name="author" content="{author}" /> |
||||
<meta name="owner" content="{author}" /> |
||||
|
||||
<meta property="og:locale" content="es_ES" /> |
||||
<meta property="og:type" content="website" /> |
||||
<meta property="og:title" data-i18n="kstats_title" content="{title}" /> |
||||
<meta property="og:description" data-i18n="kstats_description" content="{description}" /> |
||||
<meta property="og:url" content="{url}" /> |
||||
<meta property="og:site_name" content="{project}" /> |
||||
<meta property="og:image" content="{logo}" /> |
||||
<!--<meta property="fb:admins" content="FB-AppID" />--> |
||||
<meta name="twitter:card" content="summary" /> |
||||
<meta name="twitter:description" data-i18n="kstats_description" content="{description}" /> |
||||
<meta name="twitter:title" data-i18n="kstats_title" content="{title}" /> |
||||
<!--<meta name="twitter:site" content="@KStats" />--> |
||||
<!--<meta name="twitter:creator" content="@KStats" />--> |
||||
|
||||
<meta name="SKYPE_TOOLBAR" content="SKYPE_TOOLBAR_PARSER_COMPATIBLE" /> |
||||
<!--<meta name="google-site-verification" content="123456789" />--><!-- Verificación en el Google Search Console. --> |
||||
<meta name="google" content="nositelinkssearchbox" /> |
||||
<link rel="dns-prefetch" href="{url}" /> |
||||
<!--<link rel="amphtml" href="{url}index.amp.html" />--><!-- Indica si tiene página para móviles. Tecnología AMP. --> |
||||
|
||||
<link type="text/css" rel="stylesheet" data-language="CSS3" href="https://cdn.k3y.pw/css/fonts/local/Roboto.css" data-crossorigin="anonymous" charset="utf-8" /> |
||||
<link type="text/css" rel="stylesheet" data-language="CSS3" href="https://cdn.k3y.pw/css/fonts/local/RobotoMono.css" data-crossorigin="anonymous" charset="utf-8" /> |
||||
<link type="text/css" rel="stylesheet" data-language="CSS3" href="https://cdn.k3y.pw/css/fonts/local/FontAwesome5Free.css" data-crossorigin="anonymous" charset="utf-8" /> |
||||
<link type="text/css" rel="stylesheet" data-language="CSS3" href="https://unpkg.com/@highlightjs/cdn-assets@10.7.2/styles/default.min.css" data-crossorigin="anonymous" charset="utf-8" /> |
||||
|
||||
<script data-type="text/javascript" data-language="JavaScript 1.8.5" src="https://unpkg.com/mermaid@8.9.3/dist/mermaid.min.js" data-js-map="https://unpkg.com/mermaid@8.9.3/dist/mermaid.min.js.map" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
<script data-type="text/javascript" data-language="JavaScript 1.8.5" src="https://unpkg.com/@highlightjs/cdn-assets@10.7.2/highlight.min.js" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
|
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" src="https://kstats.k3y.pw/ecma/KStats.ecma.js"></script> |
||||
|
||||
<script> |
||||
|
||||
kstats = new KStats({url : "https://kstats.k3y.pw/api/SbfXgp4r3fAtuthpzXdZw2JTLKZqZFYzLhWTkQiQr4kYWsrcZvvsbKrHt/{session}/json/set"}); |
||||
|
||||
</script> |
||||
|
||||
<link type="text/css" rel="stylesheet" data-language="SASS/CSS3" href="https://wmarkdown.k3y.pw/scss/WMarkDown.css" data-scss="https://wmarkdown.k3y.pw/scss/WMarkDown.scss" data-css-map="https://wmarkdown.k3y.pw/scss/WMarkDown.css.map" data-crossorigin="anonymous" charset="utf-8" /> |
||||
<link type="text/css" rel="stylesheet" data-language="CSS3" href="https://wmarkdown.k3y.pw/css/WMarkDown.icons.css" data-crossorigin="anonymous" charset="utf-8" /> |
||||
<link type="text/css" rel="stylesheet" data-language="CSS3" href="/css/KStats.icons.css" data-crossorigin="anonymous" charset="utf-8" /> |
||||
|
||||
<style data-type="text/css" data-rel="stylesheet" data-language="CSS3" charset="utf-8"> |
||||
|
||||
html,body{ |
||||
height : 100%; |
||||
margin : 0px; |
||||
} |
||||
|
||||
</style> |
||||
|
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" src="https://wmarkdown.k3y.pw/ecma/WMarkDown.ecma.js" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" src="https://wmarkdown.k3y.pw/ecma/WMarkDown.Dictionary.ecma.js" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" src="https://wmarkdown.k3y.pw/ecma/WMarkDown.Multimedia.ecma.js" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
|
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" charset="utf-8"> |
||||
|
||||
wmarkdown = new WMarkDown({ |
||||
dictionary_links : "https://wdictionaries.k3y.pw/?es/values,own_projects,projects,digital,common,kyman", |
||||
dictionary_title : "Diccionario" |
||||
}); |
||||
|
||||
</script> |
||||
|
||||
</head> |
||||
<body class="wmarkdown ks kstats"> |
||||
<header> |
||||
<h1 class="logo"> |
||||
<a href="https://kstats.k3y.pw#"> |
||||
<span class="image"> |
||||
<span style="background-image:url('/images/KStats.png');"></span> |
||||
<img src="/images/KStats.png" alt="KStats" /> |
||||
</span> |
||||
<span class="text">KStats</span> |
||||
</a> |
||||
</h1> |
||||
<nav class="main-menu"> |
||||
<ul> |
||||
<li><a href="/" data-i18n="home" data-i18n-without="true" title="Home" target="_self"> |
||||
<span data-icon="home"></span> |
||||
<span data-i18n="home">Home</span> |
||||
</a></li> |
||||
<li><a href="/dev" data-i18n="developt" data-i18n-without="true" title="Desarrollo" target="_self"> |
||||
<span data-icon="developt"></span> |
||||
<span data-i18n="developt">Desarrollo</span> |
||||
</a></li> |
||||
<li><a href="https://git.k3y.pw/KyMAN/KStats" data-i18n="git" data-i18n-without="true" title="Git" target="_blank"> |
||||
<span data-icon="git"></span> |
||||
<span data-i18n="git">Git</span> |
||||
</a></li> |
||||
</ul> |
||||
</nav> |
||||
</header> |
||||
<main class="body" data-headers-menu-deployed="true" data-files-menu-deployed="true"> |
||||
<fieldset class="headers-menu"> |
||||
<legend data-i18n="headers_menu" title="Menu">Menu</legend> |
||||
<nav> |
||||
<ul>{menu}</ul> |
||||
</nav> |
||||
<div class="menu-buttons"> |
||||
<button type="button" data-i18n="hide" data-i18n-without="true" title="Hide" onclick="wmarkdown.hide_menu(this, event);" data-visible="true"> |
||||
<span data-icon="hide"></span> |
||||
<span data-i18n="hide">Hide</span> |
||||
</button> |
||||
<button type="button" data-i18n="show" data-i18n-without="true" title="Show" onclick="wmarkdown.show_menu(this, event);" data-visible="false"> |
||||
<span data-icon="show"></span> |
||||
<span data-i18n="show">Show</span> |
||||
</button> |
||||
</div> |
||||
</fieldset> |
||||
<fieldset class="content"> |
||||
<legend data-i18n="content" title="Content">Content</legend> |
||||
<div class="content-box">{content}</div> |
||||
</fieldset> |
||||
<fieldset class="files"> |
||||
<legend data-i18n="files" title="Files">Files</legend> |
||||
<nav> |
||||
<ul>{files}</ul> |
||||
</nav> |
||||
<div class="menu-buttons"> |
||||
<button type="button" data-i18n="hide" data-i18n-without="true" title="Hide" onclick="wmarkdown.hide_menu(this, event);" data-visible="true"> |
||||
<span data-icon="hide"></span> |
||||
<span data-i18n="hide">Hide</span> |
||||
</button> |
||||
<button type="button" data-i18n="show" data-i18n-without="true" title="Show" onclick="wmarkdown.show_menu(this, event);" data-visible="false"> |
||||
<span data-icon="show"></span> |
||||
<span data-i18n="show">Show</span> |
||||
</button> |
||||
</div> |
||||
</fieldset> |
||||
</main> |
||||
<footer> |
||||
<a href="https://www.gnu.org/licenses/gpl-3.0.txt" target="_blank" title="GPLv3" class="license"> |
||||
<span data-i18n="license_text">© 2021-2022 CopyLeft.</span> |
||||
<img src="https://www.gnu.org/graphics/gplv3-127x51.png" alt="GPLv3" /> |
||||
</a> |
||||
<div data-preload="wmarkdown-preloader"></div> |
||||
</footer> |
||||
</body> |
||||
</html> |
@ -0,0 +1 @@ |
||||
{"files":["\/mnt\/d\/git\/KStats\/Public\/dev\/ECMAScript\/index.html","\/mnt\/d\/git\/KStats\/Public\/dev\/PHP\/index.html","\/mnt\/d\/git\/KStats\/Public\/dev\/Public\/api\/index.php.html","\/mnt\/d\/git\/KStats\/Public\/dev\/Public\/ecma\/KStats.ecma.js.html","\/mnt\/d\/git\/KStats\/Public\/dev\/Public\/git_update.php.html","\/mnt\/d\/git\/KStats\/Public\/dev\/Public\/tests\/sessions.php.html","\/mnt\/d\/git\/KStats\/Public\/dev\/Public\/wmd.php.html","\/mnt\/d\/git\/KStats\/Public\/dev\/Public\/wmd_scripts.php.html","\/mnt\/d\/git\/KStats\/Public\/dev\/index.html","\/mnt\/d\/git\/KStats\/Public\/es\/bugs.html","\/mnt\/d\/git\/KStats\/Public\/es\/index.html","\/mnt\/d\/git\/KStats\/Public\/es\/project.html","\/mnt\/d\/git\/KStats\/Public\/es\/projects.html","\/mnt\/d\/git\/KStats\/Public\/es\/targets.html","\/mnt\/d\/git\/KStats\/Public\/es\/work.html","\/mnt\/d\/git\/KStats\/Public\/index.html"],"directories":["\/dev","\/dev\/ECMAScript","\/dev\/PHP","\/dev\/Public","\/dev\/Public\/api","\/dev\/Public\/ecma","\/dev\/Public\/tests","\/es"]} |
@ -0,0 +1,447 @@ |
||||
create database if not exists KStats character set utf8mb4 collate utf8mb4_general_ci; |
||||
use KStats; |
||||
|
||||
delimiter ;^ |
||||
|
||||
drop procedure if exists tables_remove;^ |
||||
create procedure tables_remove() begin |
||||
|
||||
-- Level 2. |
||||
drop table if exists SessionsUrls; |
||||
|
||||
-- Level 1. |
||||
drop table if exists Sessions; |
||||
drop table if exists IpsData; |
||||
|
||||
-- Level 0. |
||||
drop table if exists Urls; |
||||
drop table if exists Ips; |
||||
drop table if exists Tokens; |
||||
drop table if exists Settings; |
||||
|
||||
end;^ |
||||
|
||||
drop procedure if exists tables_create;^ |
||||
create procedure tables_create() begin |
||||
|
||||
-- Level 0. |
||||
create table if not exists Ips( |
||||
id integer not null auto_increment, |
||||
address varchar(39) not null, |
||||
date_in datetime not null default now(), |
||||
date_out datetime, |
||||
constraint ips_id primary key(id) |
||||
); |
||||
|
||||
create table if not exists Urls( |
||||
id integer not null auto_increment, |
||||
url varchar(2048) not null, |
||||
date_in datetime not null default now(), |
||||
date_out datetime, |
||||
constraint urls_id primary key(id) |
||||
); |
||||
|
||||
create table if not exists Tokens( |
||||
id integer not null auto_increment, |
||||
token varchar(256) not null, |
||||
enabled boolean not null default true, |
||||
pattern varchar(2048), |
||||
public boolean not null, |
||||
remarks varchar(2048), |
||||
date_in datetime not null default now(), |
||||
date_out datetime, |
||||
constraint tokens_id primary key(id) |
||||
); |
||||
|
||||
create table if not exists Settings( |
||||
id integer not null auto_increment, |
||||
name varchar(32) not null, |
||||
value varchar(256), |
||||
date_in datetime not null default now(), |
||||
date_out datetime, |
||||
constraint settings_id primary key(id) |
||||
); |
||||
|
||||
create table if not exists Countries( |
||||
id integer not null auto_increment, |
||||
name varchar(128), |
||||
code varchar(16), |
||||
date_in datetime not null default now(), |
||||
date_out datetime, |
||||
constraint countries_id primary key(id) |
||||
); |
||||
|
||||
create table if not exists Isps( |
||||
id integer not null auto_increment, |
||||
name varchar(256), |
||||
date_in datetime not null default now(), |
||||
date_out datetime, |
||||
constraint countries_id primary key(id) |
||||
); |
||||
|
||||
-- Level 1. |
||||
create table if not exists Sessions( |
||||
id integer not null auto_increment, |
||||
ip integer not null, |
||||
date_in datetime not null default now(), |
||||
date_last datetime not null default now(), |
||||
date_out datetime, |
||||
constraint sessions_id primary key(id), |
||||
constraint sessions_ip foreign key(ip) references Ips(id) |
||||
); |
||||
|
||||
create table if not exists IpsData( |
||||
id integer not null auto_increment, |
||||
ip integer not null, |
||||
country integer not null, |
||||
isp integer, |
||||
latitude decimal(9, 6), |
||||
longitude decimal(9, 6), |
||||
`data` text not null, |
||||
date_in datetime not null default now(), |
||||
date_out datetime, |
||||
constraint ips_data_id primary key(id), |
||||
constraint ips_data_ip foreign key(ip) references Ips(id), |
||||
constraint ips_data_country foreign key(country) references Countries(id), |
||||
constraint ips_data_isp foreign key(isp) references Isps(id) |
||||
); |
||||
|
||||
-- Level 2. |
||||
create table if not exists SessionsUrls( |
||||
id integer not null auto_increment, |
||||
`session` integer not null, |
||||
token integer not null, |
||||
url integer not null, |
||||
date_in datetime not null default now(), |
||||
date_last datetime not null default now(), |
||||
date_out datetime, |
||||
constraint sessions_urls_id primary key(id), |
||||
constraint sessions_urls_session foreign key(`session`) references Sessions(id), |
||||
constraint sessions_urls_token foreign key(token) references Tokens(id), |
||||
constraint sessions_urls_url foreign key(url) references Urls(id) |
||||
); |
||||
|
||||
end;^ |
||||
|
||||
drop procedure if exists tables_update;^ |
||||
create procedure tables_update() begin |
||||
|
||||
if (select 1 from information_schema.columns where table_schema = 'KStats' && table_name = 'Tokens' && column_name = 'enabled' limit 1) is null then |
||||
alter table Tokens add column enabled boolean not null default true; |
||||
end if; |
||||
if (select 1 from information_schema.columns where table_schema = 'KStats' && table_name = 'Tokens' && column_name = 'pattern' limit 1) is null then |
||||
alter table Tokens add column pattern varchar(2048); |
||||
end if; |
||||
if (select 1 from information_schema.columns where table_schema = 'KStats' && table_name = 'Tokens' && column_name = 'public' limit 1) is null then |
||||
alter table Tokens add column public boolean not null; |
||||
end if; |
||||
if (select 1 from information_schema.columns where table_schema = 'KStats' && table_name = 'Tokens' && column_name = 'remarks' limit 1) is null then |
||||
alter table Tokens add column remarks varchar(2048); |
||||
end if; |
||||
if (select 1 from information_schema.columns where table_schema = 'KStats' && table_name = 'SessionsUrls' && column_name = 'date_last' limit 1) is null then |
||||
alter table SessionsUrls add column date_last datetime not null default now(); |
||||
end if; |
||||
|
||||
end;^ |
||||
|
||||
drop procedure if exists tables_fill;^ |
||||
create procedure tables_fill() begin |
||||
|
||||
drop temporary table if exists KStatsTTSettings; |
||||
create temporary table KStatsTTSettings( |
||||
id integer not null auto_increment, |
||||
name varchar(32) not null, |
||||
value varchar(256), |
||||
date_in datetime not null default now(), |
||||
primary key(id) |
||||
); |
||||
|
||||
insert into KStatsTTSettings(name, value) values |
||||
('token_alphabet', '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'), |
||||
('token_length', 57), |
||||
('default_value', null), |
||||
('session_timeout', 900); |
||||
|
||||
insert into Settings(name, value) |
||||
select name, value from KStatsTTSettings where name not in ( |
||||
select name from Settings where date_out is null |
||||
); |
||||
|
||||
drop temporary table KStatsTTSettings; |
||||
|
||||
end;^ |
||||
|
||||
-- call tables_remove();^ |
||||
call tables_create();^ |
||||
call tables_update();^ |
||||
call tables_fill();^ |
||||
|
||||
drop function if exists settings_get;^ |
||||
create function settings_get( |
||||
$name varchar(32) |
||||
) returns varchar(256) begin |
||||
return ifnull( |
||||
(select value from Settings where date_out is null && name = $name limit 1), |
||||
(select value from Settings where date_out is null && name in ('default_value', 'value') limit 1) |
||||
); |
||||
end;^ |
||||
|
||||
drop function if exists settings_get_integer;^ |
||||
create function settings_get_integer( |
||||
$name varchar(32) |
||||
) returns integer begin |
||||
return convert(settings_get($name), integer); |
||||
end;^ |
||||
|
||||
drop procedure if exists token_create;^ |
||||
create procedure token_create( |
||||
in $public boolean, |
||||
in $pattern varchar(2048), |
||||
in $remarks varchar(2048), |
||||
out $error bigint, |
||||
out $id integer, |
||||
out $token varchar(256) |
||||
) begin |
||||
|
||||
set $id := 0; |
||||
set $error := ( |
||||
(case |
||||
when $public is null then 1 << 1 |
||||
else 0 end) | |
||||
/*(case |
||||
when $pattern is null then 1 << 2 |
||||
when $pattern = '' then 1 << 3 |
||||
else 0 end) | |
||||
(case |
||||
when $remarks is null then 1 << 4 |
||||
when $remarks = '' then 1 << 5 |
||||
else 0 end) |*/ |
||||
0 |
||||
); |
||||
|
||||
if !$error then begin |
||||
|
||||
declare $alphabet varchar(256) default settings_get('token_alphabet'); |
||||
declare `$length` integer default settings_get_integer('token_length'); |
||||
declare $l integer default length($alphabet); |
||||
|
||||
while $token is null || (select 1 from Tokens where date_out is null && token = $token limit 1) is not null do |
||||
set $token := ''; |
||||
while length($token) < `$length` do |
||||
set $token := concat($token, substring($alphabet, floor(rand() * $l) + 1, 1)); |
||||
end while; |
||||
end while; |
||||
|
||||
insert into Tokens(token, public, pattern, remarks) values($token, $public, $pattern, $remarks); |
||||
set $id := last_insert_id(); |
||||
|
||||
end;end if; |
||||
|
||||
end;^ |
||||
|
||||
drop procedure if exists ips_get;^ |
||||
create procedure ips_get( |
||||
in $ip varchar(39), |
||||
out $error bigint, |
||||
out $id integer |
||||
) begin |
||||
|
||||
set $error := (case |
||||
when $ip is null then 1 << 1 |
||||
when $ip = '' then 1 << 2 |
||||
-- when $ip not regexp '^[0-9]{1,3}(\.[0-9]{1,3}){0,3}$' then 1 << 3 |
||||
else 0 end); |
||||
|
||||
if !$error then begin |
||||
|
||||
set $id := (select id from Ips where date_out is null && address = $ip limit 1); |
||||
|
||||
if $id is null then begin |
||||
insert into Ips(address) values($ip); |
||||
set $id := last_insert_id(); |
||||
end;end if; |
||||
|
||||
end;end if; |
||||
|
||||
end;^ |
||||
|
||||
drop procedure if exists urls_get;^ |
||||
create procedure urls_get( |
||||
in $url varchar(2048), |
||||
out $error bigint, |
||||
out $id integer |
||||
) begin |
||||
|
||||
set $error := (case |
||||
when $url is null then 1 << 1 |
||||
when $url = '' then 1 << 2 |
||||
else 0 end); |
||||
|
||||
if !$error then begin |
||||
|
||||
set $id := (select id from Urls where date_out is null && url = $url limit 1); |
||||
|
||||
if $id is null then begin |
||||
insert into Urls(url) values($url); |
||||
set $id := last_insert_id(); |
||||
end;end if; |
||||
|
||||
end;end if; |
||||
|
||||
end;^ |
||||
|
||||
drop function if exists token_get;^ |
||||
create function token_get( |
||||
$token varchar(256) |
||||
) returns boolean begin |
||||
return (select id from Tokens where date_out is null && token = $token); |
||||
end;^ |
||||
|
||||
/*drop function if exists token_validate;^ |
||||
create function token_validate( |
||||
$token varchar(256), |
||||
$url varchar(2048) |
||||
) returns bigint begin |
||||
return (case |
||||
when $token is null then 1 << 0 |
||||
when $token = '' then 1 << 1'Token for YoutubeSoundsGame project.' |
||||
when $token regexp '^[0-9]+$' && convert(integer, $token) < 1 then 1 << 2 |
||||
else ifnull(( |
||||
select ( |
||||
if(enabled, 0, 1 << 4) | |
||||
if(pattern regexp (select url from Urls where date_out is null && (concat('', id) = $url || url = $url) limit 1), 0, 1 << 5) | |
||||
0 |
||||
) from Tokens where date_out is null && (concat('', id) = $token || token = $token) limit 1 |
||||
), 1 << 3) end); |
||||
end;^*/ |
||||
|
||||
drop function if exists token_validate;^ |
||||
create function token_validate( |
||||
$token integer, |
||||
$url varchar(2048) |
||||
) returns bigint begin |
||||
return (case |
||||
when $token is null then 1 << 0 |
||||
when $token < 1 then 1 << 2 |
||||
else ifnull(( |
||||
select ( |
||||
if(enabled, 0, 1 << 4) | |
||||
if(pattern is null || $url regexp pattern, 0, 1 << 5) | |
||||
if(public, 0, 1 << 6) | |
||||
0 |
||||
) from Tokens where date_out is null && id = $token limit 1 |
||||
), 1 << 3) end); |
||||
end;^ |
||||
|
||||
drop function if exists session_url_validate;^ |
||||
create function session_url_validate( |
||||
`$session` integer, |
||||
$id integer |
||||
) returns bigint begin |
||||
return if(`$session` is null, 1 << 0, (case |
||||
when $id is null then 1 << 1 |
||||
when $id < 1 then 1 << 2 |
||||
else ifnull(( |
||||
select ( |
||||
if(date_out is null, 0, 1 << 4) | |
||||
if(`session` = `$session`, 0, 1 << 5) | |
||||
0 |
||||
) from SessionsUrls where id = $id limit 1 |
||||
), 1 << 3) end)); |
||||
end;^ |
||||
|
||||
drop procedure if exists register;^ |
||||
create procedure register( |
||||
in `$session` integer, |
||||
in `$from` integer, |
||||
in $token varchar(256), |
||||
in $ip varchar(39), |
||||
in $url varchar(2048), |
||||
out $error bigint, |
||||
out $current_session integer, |
||||
out $id integer |
||||
) begin |
||||
|
||||
declare $ip_id integer; |
||||
declare $ip_error bigint; |
||||
declare $url_id integer; |
||||
declare $url_error bigint; |
||||
declare $token_id integer default token_get($token); |
||||
|
||||
call ips_get($ip, $ip_error, $ip_id); |
||||
call urls_get($url, $url_error, $url_id); |
||||
|
||||
set $error := ( |
||||
($ip_error << 1) | |
||||
($url_error << 5) | |
||||
(token_validate($token_id, $url) << 8) | |
||||
0 |
||||
); |
||||
|
||||
if !$error then begin |
||||
|
||||
if `$session` is null || (select 1 from Sessions where id = `$session` && date_out is null && ip = $ip_id && timestampdiff(second, now(), date_last) > settings_get_integer('session_timeout')) then begin |
||||
insert into Sessions(ip) values($ip_id); |
||||
set `$session` := last_insert_id(); |
||||
end;else |
||||
update Sessions set date_last := now() where id = `$session`; |
||||
end if; |
||||
set $current_session := `$session`; |
||||
|
||||
if `$from` is not null then begin |
||||
set $error := ( |
||||
(session_url_validate(`$session`, `$from`) << 15) | |
||||
0 |
||||
); |
||||
if !$error then begin |
||||
set $id := `$from`; |
||||
update SessionsUrls set date_last := now() where id = $id; |
||||
end;end if; |
||||
end;else |
||||
insert into SessionsUrls(`session`, token, url) values(`$session`, $token_id, $url_id); |
||||
set $id := last_insert_id(); |
||||
end if; |
||||
|
||||
end;end if; |
||||
|
||||
end;^ |
||||
|
||||
drop view if exists SessionsView;^ |
||||
create view SessionsView as select |
||||
sessions.id as id, |
||||
sessions.ip as ip_id, |
||||
ips.address as ip, |
||||
sessions.date_in as date_in, |
||||
sessions.date_last as date_last, |
||||
sessions.date_out as date_out, |
||||
timestampdiff(second, sessions.date_in, ifnull(sessions.date_out, sessions.date_last)) as `time`, |
||||
ips.date_in as ip_date_in |
||||
from Sessions sessions |
||||
join Ips ips on sessions.ip = ips.id |
||||
where ips.date_out is null;^ |
||||
|
||||
drop view if exists SessionsUrlsView;^ |
||||
create view SessionsUrlsView as select |
||||
sessions_urls.id as id, |
||||
sessions.id as session_id, |
||||
sessions.ip_id as ip_id, |
||||
sessions.ip as ip, |
||||
urls.id as url_id, |
||||
urls.url as url, |
||||
sessions_urls.date_in as date_in, |
||||
sessions_urls.date_last as date_last, |
||||
timestampdiff(second, sessions_urls.date_in, sessions_urls.date_last) as `time`, |
||||
sessions.date_in as session_date_in, |
||||
sessions.date_last as session_date_last, |
||||
sessions.date_out as session_date_out, |
||||
sessions.ip_date_in as ip_date_in, |
||||
sessions.`time` as session_time, |
||||
urls.date_in as url_date_in |
||||
from SessionsUrls sessions_urls |
||||
join SessionsView sessions on sessions_urls.`session` = sessions.id |
||||
join Urls urls on sessions_urls.url = urls.id |
||||
where |
||||
sessions_urls.date_out is null && |
||||
urls.date_out is null;^ |
||||
|
||||
delimiter ; |
@ -0,0 +1,302 @@ |
||||
<?php |
||||
|
||||
session_start(); |
||||
|
||||
class KStats{ |
||||
|
||||
private static $url = null; |
||||
private static $default_settings = [ |
||||
"engine" => "mysql", |
||||
"database" => "KStats", |
||||
"host" => "localhost", |
||||
"port" => 3306, |
||||
"charset" => "utf8", |
||||
"user" => "root", |
||||
"password" => "", |
||||
"connection_string" => "{engine}:dbname={database};host={host};port={port};charset={charset}", |
||||
"allow_all" => false, |
||||
"data_key" => "kstats_data", |
||||
"ip_keys_ordered" => ["HTTP_CF_CONNECTING_IP", "HTTP_X_FORWARDED_FOR", "HTTP_X_REAL_IP", "HTTP_CLIENT_IP", "REMOTE_ADDR"] |
||||
]; |
||||
private $input = []; |
||||
private $connection = null; |
||||
private $token = null; |
||||
private $type = null; |
||||
private $method = null; |
||||
private $mode = null; |
||||
private $id = null; |
||||
private $query = null; |
||||
private $session = null; |
||||
private $request_data = null; |
||||
|
||||
public static function is_dictionary($value){ |
||||
return is_array($value) && array_values($value) != $value; |
||||
} |
||||
|
||||
public static function is_secure(){ |
||||
return (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") || $_SERVER["SERVER_PORT"] == 443; |
||||
} |
||||
|
||||
private static function get_url(){ |
||||
return self::$url ? self::$url : (self::$url = ( |
||||
isset($_SERVER["HTTP_REFERER"]) ? |
||||
$_SERVER["HTTP_REFERER"] : |
||||
"http" . (self::is_secure() ? "s" : "") . "://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] |
||||
)); |
||||
} |
||||
|
||||
public function default_value($default = null, $nulls = null){ |
||||
return $default !== null || (is_bool($nulls) ? $nulls : $this->settings("nulls", null, false, false)) ? $default : $this->settings(["default_value", "default"], null, null, true); |
||||
} |
||||
|
||||
private function settings($names = null, $inputs = null, $default = null, $nulls = null){ |
||||
if(!$names) |
||||
return $this->default_value($default, $nulls); |
||||
|
||||
!is_bool($nulls) && ($nulls = $this->settings("nulls", null, false, false)); |
||||
!is_array($names) && ($names = [$names]); |
||||
|
||||
foreach(array_merge(is_array($inputs) ? (self::is_dictionary($inputs) ? [$input] : $input) : [], [$this->input, self::$default_settings]) as $input) |
||||
if(self::is_dictionary($input)) |
||||
foreach($names as $name) |
||||
if($name && isset($input[$name]) && ($nulls || $input[$name] !== null)) |
||||
return $input[$name]; |
||||
return $this->default_value($default, $nulls); |
||||
} |
||||
|
||||
public function get_ip(){ |
||||
foreach($this->settings("ip_keys_ordered") as $key){ |
||||
if(!empty($_SERVER[$key])) |
||||
return explode(",", $_SERVER[$key])[0]; |
||||
if($ips = getenv($key)) |
||||
return explode(",", $ips)[0]; |
||||
}; |
||||
return null; |
||||
} |
||||
|
||||
private function get_token(){ |
||||
return preg_replace('/^\/api\/([^\/]+)(\/.*)?$/', "$1", $_SERVER["REQUEST_URI"]); |
||||
} |
||||
|
||||
public static function string_variables($string, $variables = null, $default = null){ |
||||
|
||||
if(!is_array($variables)) |
||||
$variables = []; |
||||
elseif(self::is_dictionary($variables)) |
||||
$variables = [$variables]; |
||||
|
||||
return preg_replace_callback('/\{([^\{\}]+)\}/', function($values) use($variables){ |
||||
foreach($variables as $set) |
||||
if(isset($set[$values[1]])) |
||||
return $set[$values[1]]; |
||||
return $values[0]; |
||||
}, $string); |
||||
} |
||||
|
||||
private function query($query, $variables){ |
||||
|
||||
$used = []; |
||||
$results = [ |
||||
"tables" => [], |
||||
"variables" => [] |
||||
]; |
||||
|
||||
if(!is_array($variables)) |
||||
$variables = []; |
||||
elseif(self::is_dictionary($variables)) |
||||
$variables = [$variables]; |
||||
|
||||
preg_replace_callback('/\@([a-zA-Z0-9_]+)/', function($values) use(&$used){ |
||||
!in_array($values[1], $used) && ($used[] = $values[1]); |
||||
}, is_array($variables) ? ($query = preg_replace_callback('/\{([^\{\}]+)\}/', function($values) use($variables){ |
||||
foreach($variables as $set) |
||||
if(isset($set[$values[1]])) |
||||
return ( |
||||
$set[$values[1]] === null ? "null" : ( |
||||
is_bool($set[$values[1]]) ? ($set[$values[1]] ? "true" : "false") : ( |
||||
is_string($set[$values[1]]) ? "'" . preg_replace('/([\\\\\'])/', "\\\\$1", $set[$values[1]]) . "'" : ( |
||||
$set[$values[1]] |
||||
)))); |
||||
return "null"; |
||||
}, $query)) : $query); |
||||
|
||||
if(!empty($used)){ |
||||
$subquery = ""; |
||||
foreach($used as $key) |
||||
$subquery .= ($subquery ? "," : "") . " @" . $key . " as '" . $key . "'"; |
||||
$query .= (preg_match('/;$/', $query) ? "" : ";") . "select" . $subquery . ";"; |
||||
} |
||||
|
||||
if(!$this->connection){ |
||||
$this->connection = new \PDO(self::string_variables($this->settings(["connection_string", "string_connection"]), [ |
||||
"engine" => $this->settings(["connection_engine", "engine"]), |
||||
"database" => $this->settings(["connection_database", "database"]), |
||||
"host" => $this->settings(["connection_host", "host"]), |
||||
"port" => $this->settings(["connection_port", "port"]), |
||||
"charset" => $this->settings(["connection_charset", "charset"]) |
||||
]), $this->settings(["connection_user", "user"]), $this->settings(["connection_password", "password"])); |
||||
$this->connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); |
||||
$this->connection->beginTransaction(); |
||||
}; |
||||
|
||||
$this->query = $query; |
||||
|
||||
($statement = $this->connection->prepare($query))->execute(); |
||||
|
||||
do{ |
||||
try{ |
||||
$table = []; |
||||
foreach($statement->rowCount() == 0 ? [] : $statement->fetchAll(\PDO::FETCH_ASSOC) as $new_row){ |
||||
$row = []; |
||||
foreach($new_row as $key => $value){ |
||||
if($value && is_string($value) && in_array($value[0], ["[", "{"])){ |
||||
try{ |
||||
$row[$key] = json_decode(utf8_encode($value), true); |
||||
}catch(\Exception $exception){} |
||||
!$row[$key] && ($row[$key] = utf8_encode($value)); |
||||
}else |
||||
$row[$key] = $value; |
||||
}; |
||||
$table[] = $row; |
||||
}; |
||||
$results["tables"][] = $table; |
||||
}catch(\Exception $exception){}; |
||||
}while($statement->nextRowset()); |
||||
|
||||
if(preg_match('/(,\s+?|\()\@/', $query)){ |
||||
$l = count($results["tables"]) - 1; |
||||
foreach($results["tables"][$l][0] as $key => $value) |
||||
$results["variables"][$key] = $value; |
||||
unset($results["tables"][$l]); |
||||
}; |
||||
|
||||
$this->connection->commit(); |
||||
|
||||
return $results; |
||||
} |
||||
|
||||
private function save(){ |
||||
|
||||
$results = null; |
||||
|
||||
if(!in_array($this->type, ["js", "ecma"]) || $this->settings("allow_all")){ |
||||
|
||||
// isset($_SERVER["HTTP_REFERER"]) && |
||||
$results = $this->query("call register({session}, {from}, {token}, {ip}, {url}, @error, @current_session, @id);", [ |
||||
"session" => $this->session ? $this->session : null, |
||||
"from" => $this->id ? $this->id : null, |
||||
"token" => $this->get_token(), |
||||
"ip" => $this->get_ip(), |
||||
"url" => $this->request_data && isset($this->request_data["url"]) ? $this->request_data["url"] : self::get_url() |
||||
]); |
||||
|
||||
$results && |
||||
($_SESSION["kstats_id"] = $results["variables"]["current_session"]); |
||||
|
||||
}; |
||||
|
||||
return $results; |
||||
} |
||||
|
||||
private function print($data){ |
||||
|
||||
switch($this->type){ |
||||
case "js": |
||||
header("content-type: text/javascript"); |
||||
echo file_get_contents(__DIR__ . "/../Public/js/KStats.js"); |
||||
break; |
||||
case "ecma": |
||||
header("content-type: text/javascript"); |
||||
echo file_get_contents(__DIR__ . "/../Public/ecma/KStats.ecma.js"); |
||||
break; |
||||
case "image": |
||||
case "img": |
||||
header("content-type: image/png"); |
||||
echo file_get_contents(__DIR__ . "/../Public/images/min.png"); |
||||
break; |
||||
case "css": |
||||
header("content-type: text/css"); |
||||
echo "kstats-tag-link::after{content : '" . $data . "';}"; |
||||
break; |
||||
case "json": |
||||
header("content-type: application/json"); |
||||
echo json_encode([ |
||||
"ok" => true, |
||||
"code" => 200, |
||||
"data" => $data |
||||
]); |
||||
break; |
||||
case "test": |
||||
header("content-type: text/javascript"); |
||||
echo "console.log(" . json_encode([ |
||||
"session" => $_SESSION |
||||
]) . ");console.log(document.cookie.split(';'));"; |
||||
break; |
||||
default: |
||||
header("content-type: text/plain"); |
||||
echo ""; |
||||
break; |
||||
}; |
||||
|
||||
exit(0); |
||||
|
||||
} |
||||
|
||||
public function __construct($input = null){ |
||||
|
||||
is_array($input) && ($this->input = $input); |
||||
|
||||
if(preg_match('/^\/api\/([^\/]+)\/([^\/]+)\/([^\/]+)\/([^\/\?]+)(\/([^\?]+))?/', $_SERVER["REQUEST_URI"], $matches)){ |
||||
|
||||
$data_key = $this->settings("data_key"); |
||||
|
||||
$this->token = $matches[1]; |
||||
$this->session = intval($matches[2]); |
||||
$this->type = $matches[3]; |
||||
|
||||
foreach([$_POST, $_GET, $_COOKIE] as $set) |
||||
if(isset($set[$data_key])){ |
||||
$this->request_data = json_decode(base64_decode(urldecode($set[$data_key])), true); |
||||
break; |
||||
}; |
||||
|
||||
// print_r(["request_data", $this->request_data, "get" => $_GET]); |
||||
|
||||
switch($this->method = $matches[4]){ |
||||
case "set": |
||||
isset($matches[6]) && $matches[6] && ($this->id = intval($matches[6])); |
||||
$response = $this->save(); |
||||
$this->print(array_merge(is_array($response) ? $response : [], [ |
||||
"url" => self::get_url(), |
||||
"query" => $this->query |
||||
])); |
||||
}; |
||||
|
||||
}; |
||||
|
||||
$this->print(false); |
||||
|
||||
} |
||||
|
||||
public function close(){ |
||||
|
||||
if($this->connection){ |
||||
try{ |
||||
$this->connection->commit(); |
||||
}catch(\Exception $exception){ |
||||
try{ |
||||
$this->connection->rollback(); |
||||
}catch(\Exception $subexception){}; |
||||
}; |
||||
}; |
||||
$this->connection = null; |
||||
|
||||
} |
||||
|
||||
public function __destruct(){ |
||||
|
||||
$this->close(); |
||||
|
||||
} |
||||
|
||||
}; |
@ -0,0 +1,8 @@ |
||||
<?php |
||||
|
||||
foreach([ |
||||
"KStats", |
||||
"KStats.Secrets" |
||||
] as $file) |
||||
if(file_exists($file = __DIR__ . "/" . $file . ".php")) |
||||
include $file; |
@ -0,0 +1,7 @@ |
||||
Header set Access-Control-Allow-Origin "*" |
||||
RewriteEngine On |
||||
#RewriteCond %{REQUEST_METHOD} OPTIONS |
||||
RewriteCond %{REQUEST_FILENAME} !-d |
||||
RewriteCond %{REQUEST_FILENAME} !-f |
||||
#RewriteCond %{REQUEST_URI} !^/index.php$ |
||||
RewriteRule ^api(.*)$ /api/index.php [NC,L,QSA] |
@ -0,0 +1,5 @@ |
||||
<?php |
||||
|
||||
include __DIR__ . "/../../PHP/include.php"; |
||||
|
||||
$kstats = new KStats(KStats\Secrets::connection); |
@ -0,0 +1,247 @@ |
||||
KStats = function(input){ |
||||
|
||||
const self = this, |
||||
default_settings = { |
||||
autostart : true, |
||||
nulls : false, |
||||
default_vaalue : null, |
||||
ajax_timeout : 2000, |
||||
settings_overwrite : false, |
||||
kstats_url : "https://kstats.k3y.pw/api/uCDY3brWxEJrJywm2sFcKo1d8oaUdmxTTrv3VGuhpyRDpPYXyKeHWeknh/{session}/ecma/set", |
||||
frames_per_second : 1, |
||||
milliseconds_per_connection : 2000, |
||||
session_cookie_name : "kstats_session_id", |
||||
session_timeout : 60000, |
||||
data_key : "kstats_data" |
||||
}, |
||||
custom = {}, |
||||
threads = []; |
||||
let started = false, |
||||
thread = null, |
||||
last_connection = 0, |
||||
milliseconds_per_connection = null, |
||||
register_thread = null, |
||||
id = null, |
||||
url = null, |
||||
session = null, |
||||
data_key = null; |
||||
|
||||
const default_value = this.default_value = (_default, nulls) => _default !== undefined && (_default !== null || (typeof nulls == "boolean" ? nulls : settings("nulls", null, false, false))) ? _default : settings(["default_value", "default"], null, null, true); |
||||
|
||||
const settings = this.settings = (names, inputs, _default, nulls) => { |
||||
if(!names) |
||||
return default_value(_default, nulls); |
||||
|
||||
const l = (names.push ? names : names = [names]).length, |
||||
m = (inputs = (inputs ? inputs.push ? inputs : [inputs] : []).concat([input, custom, default_settings])).length; |
||||
|
||||
typeof nulls != "boolean" && (nulls = settings("nulls", null, false, false)); |
||||
|
||||
for(let j = 0; j < m; j ++) |
||||
if(typeof inputs[j] == "object") |
||||
for(let i = 0; i < l; i ++) |
||||
if(names[i] && inputs[j][names[i]] !== undefined && (nulls || inputs[j][names[i]] !== null)) |
||||
return inputs[j][names[i]]; |
||||
return default_value(_default, nulls); |
||||
}; |
||||
|
||||
const load = this.load = (url, callback) => { |
||||
|
||||
let ended = false; |
||||
const ajax = new XMLHttpRequest(), |
||||
timeout = settings(["ajax_timeout", "load_timeout", "timeout"]), |
||||
date = Date.now(), |
||||
end = message => { |
||||
if(ended) |
||||
return; |
||||
ended = true; |
||||
typeof callback == "function" && callback(ajax.responseText, ajax.status, ajax.readyState, message == "OK", message); |
||||
}; |
||||
|
||||
ajax.open("get", url, true); |
||||
ajax.timeout = timeout; |
||||
ajax.onreadystatechange = () => { |
||||
if(ended) |
||||
return; |
||||
if(ajax.readyState == 4) |
||||
end((ajax.status >= 200 && ajax.status < 300) || [301, 302, 304].includes(ajax.status) ? "OK" : "HTTP_ERROR"); |
||||
else if(Date.now() - date > timeout) |
||||
end("FORCED_TIMEOUT"); |
||||
}; |
||||
ajax.send(null); |
||||
|
||||
ajax.onabort = () => end("ABORTED"), |
||||
ajax.onerror = () => end("ERROR"); |
||||
ajax.ontimeout = () => end("TIMEOUT"); |
||||
|
||||
return ajax; |
||||
}; |
||||
|
||||
const settings_add_i = (items, overwrite, callback, i) => { |
||||
|
||||
if(i >= items.length){ |
||||
typeof callback == "function" && callback(); |
||||
return; |
||||
}; |
||||
|
||||
if(items[i]){ |
||||
if(typeof items[i] == "string"){ |
||||
|
||||
let json; |
||||
|
||||
try{ |
||||
json = JSON.parse(items[i]); |
||||
}catch(exception){}; |
||||
|
||||
if(json) |
||||
settings_add_i(json.push ? json : [json], overwrite, end, 0); |
||||
else |
||||
load(json, response => { |
||||
try{ |
||||
json = JSON.parse(response); |
||||
}catch(exception){}; |
||||
if(json) |
||||
settings_add_i(json.push ? json : [json], overwrite, end, 0); |
||||
else |
||||
end(); |
||||
}); |
||||
|
||||
return; |
||||
}; |
||||
if(typeof items[i] == "object"){ |
||||
if(items[i].push){ |
||||
settings_add_i(items[i], overwrite, end, 0); |
||||
return; |
||||
}; |
||||
for(const key in items[i]) |
||||
(overwrite || custom[key] === undefined) && (custom[key] = items[i][key]); |
||||
}; |
||||
}; |
||||
|
||||
end(); |
||||
|
||||
}; |
||||
|
||||
const settings_add = this.settings_add = (items, overwrite, callback) => settings_add_i(items ? items.push ? items : [items] : [], typeof overwrite == "boolean" ? overwrite : settings(["settings_overwrite", "overwrite"]), callback, 0); |
||||
|
||||
const threads_method = () => threads.forEach(thread => thread && thread()); |
||||
|
||||
const threads_start = this.threads_start = () => thread === null && (thread = setInterval(threads_method, 1000 / settings(["frames_per_second", "fps"]))); |
||||
|
||||
this.threads_stop = () => { |
||||
if(thread === null) |
||||
return; |
||||
|
||||
clearInterval(thread); |
||||
thread = null; |
||||
|
||||
}; |
||||
|
||||
const threads_add = this.threads_add = method => { |
||||
if(typeof method != "function") |
||||
return null; |
||||
|
||||
let i = 0; |
||||
const l = threads.length; |
||||
|
||||
for(; i < l; i ++) |
||||
if(!threads[i]) |
||||
break; |
||||
|
||||
threads[i] = method; |
||||
|
||||
return i; |
||||
}; |
||||
|
||||
const threads_remove = this.threads_remove = i => !isNaN(i) && threads[i] && (threads[i] = null); |
||||
|
||||
const string_variables = this.string_variables = (string, variables, _default) => { |
||||
|
||||
if(!variables) |
||||
variables = []; |
||||
else if(!variables.push) |
||||
variables = [variables]; |
||||
|
||||
for(let i = variables.length - 1; i >= 0; i --) |
||||
typeof variables[i] != "object" && (variables = variables.splice(i, 1)); |
||||
|
||||
const l = variables.length; |
||||
|
||||
return string.replace(/\{([^\{\}]+)\}/g, (...arguments) => { |
||||
for(let i = 0; i < l; i ++) |
||||
if(variables[i][arguments[1]] !== undefined) |
||||
return variables[i][arguments[1]]; |
||||
return _default !== undefined ? _default : arguments[0]; |
||||
}); |
||||
}; |
||||
|
||||
const update = () => load(tmp = string_variables(url || (url = settings(["kstats_url", "url"])), { |
||||
session : session |
||||
}) + (id ? "/" + id : "") + "?" + (data_key || (data_key = settings("data_key"))) + "=" + btoa(JSON.stringify({ |
||||
url : window.location.href.replace(/^([^#]+)(\#.*)?$/, "$1") |
||||
})), (...arguments) => { |
||||
if(!arguments[0]) |
||||
return; |
||||
|
||||
const data = JSON.parse(arguments[0]), |
||||
current_session = Number(data.data.variables.current_session); |
||||
|
||||
session != current_session && (document.cookie = settings("session_cookie_name") + "=" + (session = current_session) + ";expires=" + new Date(Date.now() + settings("session_timeout")).toUTCString() + ";path=/;SameSite=Lax"); |
||||
|
||||
if(id === null){ |
||||
id = data.data.variables.id; |
||||
addEventListener("beforeunload", update); |
||||
}; |
||||
|
||||
}); |
||||
|
||||
const register_event = () => { |
||||
|
||||
const date = Date.now(); |
||||
|
||||
if(date - last_connection > milliseconds_per_connection){ |
||||
last_connection = date; |
||||
update(); |
||||
}; |
||||
|
||||
}; |
||||
|
||||
this.start = () => { |
||||
|
||||
if(started) |
||||
return; |
||||
started = true; |
||||
|
||||
settings_add(settings("settings_files"), true, () => { |
||||
|
||||
const session_pattern = new RegExp("^" + settings("session_cookie_name") + "=(.+)$"); |
||||
|
||||
milliseconds_per_connection = settings("milliseconds_per_connection"); |
||||
|
||||
!decodeURIComponent(document.cookie).split(";").some(cookie => { |
||||
|
||||
const matches = cookie.trim().match(session_pattern); |
||||
|
||||
if(matches){ |
||||
session = Number(matches[1]); |
||||
return true; |
||||
}; |
||||
|
||||
}) && (session = 0); |
||||
|
||||
threads_start(); |
||||
register_thread = threads_add(register_event); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
const construct = () => { |
||||
|
||||
settings("autostart") && self.start(); |
||||
|
||||
}; |
||||
|
||||
construct(); |
||||
|
||||
}; |
@ -0,0 +1,4 @@ |
||||
<?php |
||||
|
||||
header("content-type: text/plain"); |
||||
echo shell_exec("git pull 2>&1"); |
After Width: | Height: | Size: 546 B |
@ -0,0 +1,33 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en" dir="ltr"> |
||||
<head> |
||||
<title data-i18n="contact_book_title">ContactBook</title> |
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> |
||||
<meta charset="utf-8" /> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" /> |
||||
|
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" charset="utf-8"> |
||||
|
||||
let session = null; |
||||
|
||||
console.log(document.cookie); |
||||
|
||||
!decodeURIComponent(document.cookie).split(";").some(cookie => { |
||||
|
||||
const matches = cookie.trim().match(/^session_id_test\=(.*)$/); |
||||
|
||||
if(matches){ |
||||
session = Number(matches[1]); |
||||
return true; |
||||
}; |
||||
|
||||
}) && |
||||
(document.cookie = "session_id_test=" + (session = Math.random() * 999999 >> 0) + ";expires=" + new Date(Date.now() + 60000).toUTCString() + ";path=/"); |
||||
|
||||
console.log(session); |
||||
|
||||
</script> |
||||
|
||||
</head> |
||||
<body></body> |
||||
</html> |
@ -0,0 +1,23 @@ |
||||
<?php |
||||
|
||||
session_start(); |
||||
if(isset($_GET["del"])){ |
||||
session_destroy(); |
||||
// setcookie("id", null, time() - 3600, "/cookies/", "kstats.local", false, true); |
||||
}; |
||||
if(!isset($_COOKIE["id"])){ |
||||
setcookie("id", random_int(0, 999999), [ |
||||
"expires" => time() + (86400 * 30), |
||||
"path" => "/", |
||||
"domain" => $_SERVER['SERVER_NAME'], |
||||
"secure" => false, |
||||
"httponly" => true, |
||||
"samesite" => "Strict" |
||||
]); |
||||
echo "PASA<br />\n"; |
||||
print_r(array_keys($_COOKIE)); |
||||
}; |
||||
echo ( |
||||
(isset($_SESSION["id"]) ? $_SESSION["id"] : $_SESSION["id"] = random_int(0, 99999999)) . "<br />\n" . |
||||
$_COOKIE["id"] |
||||
); |
@ -0,0 +1,29 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en" dir="ltr"> |
||||
<head> |
||||
<title data-i18n="contact_book_title">ContactBook</title> |
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> |
||||
<meta charset="utf-8" /> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" /> |
||||
|
||||
<!-- <script data-type="text/javascript" data-language="EMCAScript 2015" src="https://kstats.k3y.pw/api/uCDY3brWxEJrJywm2sFcKo1d8oaUdmxTTrv3VGuhpyRDpPYXyKeHWeknh/{session}/ecma/set" data-crossorigin="anonymous" charset="utf-8"></script> --> |
||||
<!-- <script data-type="text/javascript" data-language="EMCAScript 2015" src="/api/uCDY3brWxEJrJywm2sFcKo1d8oaUdmxTTrv3VGuhpyRDpPYXyKeHWeknh/{session}/ecma/set" data-crossorigin="anonymous" charset="utf-8"></script> --> |
||||
<!-- <script data-type="text/javascript" data-language="EMCAScript 2015" src="https://kstats.k3y.pw/ecma/KStats.ecma.js" data-crossorigin="anonymous" charset="utf-8"></script> --> |
||||
<script data-type="text/javascript" data-language="EMCAScript 2015" src="/ecma/KStats.ecma.js" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" charset="utf-8"> |
||||
|
||||
kstats = new KStats({ |
||||
// url : "https://kstats.k3y.pw/api/uCDY3brWxEJrJywm2sFcKo1d8oaUdmxTTrv3VGuhpyRDpPYXyKeHWeknh/{session}/json/set" |
||||
url : "/api/uCDY3brWxEJrJywm2sFcKo1d8oaUdmxTTrv3VGuhpyRDpPYXyKeHWeknh/{session}/json/set" |
||||
}); |
||||
|
||||
</script> |
||||
|
||||
<!-- <script data-type="text/javascript" data-language="JavaScript 1.8.5" src="https://kstats.k3y.pw/api/uCDY3brWxEJrJywm2sFcKo1d8oaUdmxTTrv3VGuhpyRDpPYXyKeHWeknh/{session}/test/set" data-crossorigin="anonymous" charset="utf-8"></script> --> |
||||
<!-- <script data-type="text/javascript" data-language="JavaScript 1.8.5" src="/api/uCDY3brWxEJrJywm2sFcKo1d8oaUdmxTTrv3VGuhpyRDpPYXyKeHWeknh/{session}/test/set" data-crossorigin="anonymous" charset="utf-8"></script> --> |
||||
|
||||
</head> |
||||
<body> |
||||
<a href="tests">Test</a> |
||||
</body> |
||||
</html> |
@ -0,0 +1,6 @@ |
||||
<?php |
||||
|
||||
include __DIR__ . "/../../WMarkDown/PHP/include.php"; |
||||
include __DIR__ . "/../PHP/KStats.Secrets.php"; |
||||
|
||||
$wmd = new WMarkDown(KStats\Secrets::wmarkdown); |
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
include __DIR__ . "/../../WMarkDown/PHP/include.php"; |
||||
include __DIR__ . "/../PHP/KStats.Secrets.php"; |
||||
|
||||
$wmd = new WMarkDown(array_merge([ |
||||
"action" => "update_scripts", |
||||
"author" => "KyMAN", |
||||
"project" => "KStats", |
||||
"class" => "KStats", |
||||
"object" => "kstats", |
||||
"url" => "https://kstats.k3y.pw", |
||||
"project_author" => "KyMAN", |
||||
"key_words" => "contact,book,contact book,kyman,secrets,notes", |
||||
"logo" => "/images/KStats.png", |
||||
"language" => "es", |
||||
"wmd_file" => "/../WMarkDown/HTML/script.w.md", |
||||
"wmd_file_empty" => "/../WMarkDown/HTML/file.w.md", |
||||
"ignore_script_paths" => [], |
||||
"only" => "/Public" |
||||
], KStats\Secrets::wmarkdown)); |
@ -0,0 +1,24 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# ECMAScript |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/dev/Public/ecma/KStats.ecma.js.w.md]] |
||||
|
||||
|
||||
|
||||
[[html_data { |
||||
"title" : "ECMAScript - KStats", |
||||
"url" : "https://kstats.k3y.pw/dev/ECMAScript/index.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "contact,book,contact book,kyman,secrets,notes,developt,desarrollo,programación,ecmascript", |
||||
"description" : "Parte ECMAScript del KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,36 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# PHP |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/dev/Public/api/index.php.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/dev/Public/git_update.php.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/dev/Public/tests/sessions.php.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/dev/Public/wmd.php.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/dev/Public/wmd_scripts.php.w.md]] |
||||
|
||||
|
||||
|
||||
[[html_data { |
||||
"title" : "PHP - KStats", |
||||
"url" : "https://kstats.k3y.pw/dev/PHP/index.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "contact,book,contact book,kyman,secrets,notes,developt,desarrollo,programación,php", |
||||
"description" : "Parte PHP del KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,23 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# index.php |
||||
|
||||
```txt |
||||
/Public/api/index.php |
||||
``` |
||||
|
||||
[[html_data { |
||||
"title" : "index.php - KStats", |
||||
"url" : "https://kstats.k3y.pw/Public/api/index.php.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "contact,book,contact book,kyman,secrets,notes,developt,desarrollo,programación,main", |
||||
"description" : "index.php del KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,268 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# KStats.ecma.js |
||||
|
||||
```txt |
||||
/Public/ecma/KStats.ecma.js |
||||
``` |
||||
|
||||
## [[plain KStats.default_value]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.default_value |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash a1841f42c4352bb7f9f7bb87f89ff6fb |
||||
#_default - optional Parámetro _default |
||||
#nulls - optional Parámetro nulls |
||||
#return - - Retorno. |
||||
]] |
||||
|
||||
## [[plain KStats.settings]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.settings |
||||
@see KStats.default_value |
||||
@see KStats.settings |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash 97e5deffc108b21fd26d5aa45248e1e0 |
||||
#names - optional Parámetro names |
||||
#inputs - optional Parámetro inputs |
||||
#_default - optional Parámetro _default |
||||
#nulls - optional Parámetro nulls |
||||
#return - - Retorno. |
||||
]] |
||||
|
||||
## [[plain KStats.load]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.load |
||||
@see KStats.settings |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash 5d29594ed33dec2bfa759d0f4dc71d16 |
||||
#url - optional Parámetro url |
||||
#callback - optional Parámetro callback |
||||
#return - - Retorno. |
||||
]] |
||||
|
||||
## [[plain KStats.settings_add_i]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.settings_add_i |
||||
@see KStats.settings_add_i |
||||
@see KStats.load |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access private |
||||
@hash f91128cfea61bf0ad16c2d04ba1a1822 |
||||
#items - optional Parámetro items |
||||
#overwrite - optional Parámetro overwrite |
||||
#callback - optional Parámetro callback |
||||
#i - optional Parámetro i |
||||
]] |
||||
|
||||
## [[plain KStats.settings_add]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.settings_add |
||||
@see KStats.settings_add_i |
||||
@see KStats.settings |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash e6787641e9592c9293090db05ce49585 |
||||
#items - optional Parámetro items |
||||
#overwrite - optional Parámetro overwrite |
||||
#callback - optional Parámetro callback |
||||
#return - - Retorno. |
||||
]] |
||||
|
||||
## [[plain KStats.threads_method]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.threads_method |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access private |
||||
@hash ab9bbde1ed980d410067bd829ca8d957 |
||||
#return - - Retorno. |
||||
]] |
||||
|
||||
## [[plain KStats.threads_start]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.threads_start |
||||
@see KStats.settings |
||||
@see KStats.threads_method |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash 1090cef55ff368e19f68fb0f13262eb0 |
||||
#return - - Retorno. |
||||
]] |
||||
|
||||
## [[plain KStats.threads_stop]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.threads_stop |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash c1b6d79c278d28a090faf96255fa0c34 |
||||
]] |
||||
|
||||
## [[plain KStats.threads_add]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.threads_add |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash 7b36976fb1531ed998a2a76196d98172 |
||||
#method - optional Parámetro method |
||||
#return - - Retorno. |
||||
]] |
||||
|
||||
## [[plain KStats.threads_remove]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.threads_remove |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash e005119bc808e1eefdbfec228fac6441 |
||||
#i - optional Parámetro i |
||||
#return - - Retorno. |
||||
]] |
||||
|
||||
## [[plain KStats.string_variables]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.string_variables |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash e372ccebccaf8f8d06c24f79d629e7a6 |
||||
#string - optional Parámetro string |
||||
#variables - optional Parámetro variables |
||||
#_default - optional Parámetro _default |
||||
]] |
||||
|
||||
## [[plain KStats.update]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.update |
||||
@see KStats.load |
||||
@see KStats.string_variables |
||||
@see KStats.settings |
||||
@see KStats.update |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access private |
||||
@hash 735287af679b35ef121b59e52ba3dbab |
||||
#return - - Retorno. |
||||
]] |
||||
|
||||
## [[plain KStats.register_event]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.register_event |
||||
@see KStats.update |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access private |
||||
@hash b6094c4945ffa697ddde38d0158e4f7e |
||||
]] |
||||
|
||||
## [[plain KStats.start]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.start |
||||
@see KStats.settings_add |
||||
@see KStats.settings |
||||
@see KStats.threads_start |
||||
@see KStats.threads_add |
||||
@see KStats.register_event |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access public |
||||
@hash 0414214855b51d79636becf6f5b3bdc1 |
||||
]] |
||||
|
||||
## [[plain KStats.construct]] |
||||
|
||||
[[wdoc |
||||
Método object. |
||||
@name KStats.construct |
||||
@see KStats.settings |
||||
@see KStats.start |
||||
@lang ECMAScript |
||||
@author KyMAN |
||||
@since 20220320 |
||||
@version 20220320 |
||||
@access private |
||||
@hash 88422b1f098ab1ff14b3b73c5b3f48f5 |
||||
]] |
||||
|
||||
[[html_data { |
||||
"title" : "KStats.ecma.js - KStats", |
||||
"url" : "https://kstats.k3y.pw/Public/ecma/KStats.ecma.js.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "contact,book,contact book,kyman,secrets,notes,developt,desarrollo,programación,cma", |
||||
"description" : "KStats.ecma.js del KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,23 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# git_update.php |
||||
|
||||
```txt |
||||
/Public/git_update.php |
||||
``` |
||||
|
||||
[[html_data { |
||||
"title" : "git_update.php - KStats", |
||||
"url" : "https://kstats.k3y.pw/Public/git_update.php.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "contact,book,contact book,kyman,secrets,notes,developt,desarrollo,programación,main", |
||||
"description" : "git_update.php del KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,23 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# sessions.php |
||||
|
||||
```txt |
||||
/Public/tests/sessions.php |
||||
``` |
||||
|
||||
[[html_data { |
||||
"title" : "sessions.php - KStats", |
||||
"url" : "https://kstats.k3y.pw/Public/tests/sessions.php.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "contact,book,contact book,kyman,secrets,notes,developt,desarrollo,programación,main", |
||||
"description" : "sessions.php del KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,23 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# wmd.php |
||||
|
||||
```txt |
||||
/Public/wmd.php |
||||
``` |
||||
|
||||
[[html_data { |
||||
"title" : "wmd.php - KStats", |
||||
"url" : "https://kstats.k3y.pw/Public/wmd.php.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "contact,book,contact book,kyman,secrets,notes,developt,desarrollo,programación,main", |
||||
"description" : "wmd.php del KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,23 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# wmd_scripts.php |
||||
|
||||
```txt |
||||
/Public/wmd_scripts.php |
||||
``` |
||||
|
||||
[[html_data { |
||||
"title" : "wmd_scripts.php - KStats", |
||||
"url" : "https://kstats.k3y.pw/Public/wmd_scripts.php.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "contact,book,contact book,kyman,secrets,notes,developt,desarrollo,programación,main", |
||||
"description" : "wmd_scripts.php del KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,52 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220402, |
||||
"version" : 20220402 |
||||
}]] |
||||
# Bugs y errores |
||||
|
||||
En esta sección de la Web se detallarán los errores y Bugs encontrados durante el desarrollo y uso |
||||
de la herramienta. |
||||
|
||||
## 2022040200 - Redirección IP con Cloudflare y Nginx |
||||
|
||||
A la hora de capturar la dirección IP del usuario sobre Cloudflare nos encontramos con un problema |
||||
el cual, el paquete de datos HTTP altera la cabecera al paso por Cloudflare, siendo el cliente |
||||
Cloudflare y no el cliente real al que hacemos referencia. Las variables de los datos META también |
||||
son alterados, incluyendo el REMOTE_ADDR. |
||||
|
||||
[X] Arreglar el problema con la configuración actual sobre Nginx contra Cloudflare. |
||||
|
||||
> [[! note NOTA]]: Cloudflare agrega un nuevo valor en los META del paquete HTTP llamado |
||||
HTTP_CF_CONNECTING_IP, el cual puede ser recogido directamente por PHP mediante $_SERVER o cargado |
||||
indirectamente con los datos de cabecera. Se pueden alterar los datos de entrada del REMOTE_ADDR |
||||
desde Nginx poniendo como valor dicha cabecera pero al ser accesible desde PHP de esta forma, |
||||
simplemente se alterará la cadena de llaves de acceso a las IPs. |
||||
|
||||
```php |
||||
|
||||
$ip = null; |
||||
|
||||
foreach(["HTTP_CF_CONNECTING_IP", "HTTP_X_FORWARDED_FOR", "HTTP_X_REAL_IP", "HTTP_CLIENT_IP", "REMOTE_ADDR"] as $key){ |
||||
if(!empty($_SERVER[$key])) |
||||
$ip = explode(",", $_SERVER[$key])[0]; |
||||
if($ips = getenv($key)) |
||||
$ip = explode(",", $ips)[0]; |
||||
}; |
||||
|
||||
echo $ip; |
||||
|
||||
``` |
||||
|
||||
[[html_data { |
||||
"title" : "KStats - Bugs", |
||||
"url" : "https://kstats.k3y.pw/es/bugs.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220402, |
||||
"version" : 20220402, |
||||
"key_words" : "kstats,stats,statistics,kyman,wmd,wmarkdown,documentación,bugs,fallos,errores,arreglos,problemas,fix", |
||||
"description" : "Bugs y errores del proyecto KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "https://kstats.k3y.pw/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,37 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220316, |
||||
"version" : 20220320 |
||||
}]] |
||||
# KStats |
||||
|
||||
Documentación del proyecto KStats, proyecto que hace registros masivos de movimientos de los |
||||
usuarios dentro de las Webs registradas por los Tokens. |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/es/project.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/es/work.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/es/projects.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/es/bugs.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/es/targets.w.md]] |
||||
|
||||
[[html_data { |
||||
"title" : "KStats - Documentación", |
||||
"url" : "https://kstats.k3y.pw/es/", |
||||
"author" : "KyMAN", |
||||
"since" : 20220316, |
||||
"version" : 20220320, |
||||
"key_words" : "kstats,stats,statistics,kyman,wmd,wmarkdown,documentación", |
||||
"description" : "Documentación del proyecto KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "https://kstats.k3y.pw/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,24 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220316, |
||||
"version" : 20220320 |
||||
}]] |
||||
# KStats |
||||
|
||||
El proyecto KStats no es más que un proyecto de gestión estadística de proceso paralelo a la |
||||
ejecución de la Web el cual centraliza los datos en una base de datos común, lo que permite que un |
||||
proyecto KStats levantado gestione más de un sitio Web. Requiere del CORS deshabilitado en el |
||||
entorno API. |
||||
|
||||
[[html_data { |
||||
"title" : "KStats - Idioma", |
||||
"url" : "https://kstats.k3y.pw/es/projects.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220316, |
||||
"version" : 20220320, |
||||
"key_words" : "kstats,stats,statistics,kyman,wmd,wmarkdown,documentación", |
||||
"description" : "Documentación del proyecto KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "https://kstats.k3y.pw/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,54 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# Proyectos |
||||
|
||||
En esta sección se mostrarán los proyectos dependientes ya sea del KStats, como el KStats de otros |
||||
proyectos. Para empezar dicha lista, empezaremos con los proyectos de los cuales depende el KStats, |
||||
los cuales son los siguientes: |
||||
|
||||
[[links_group [{ |
||||
"images" : ["https://wmarkdown.k3y.pw/images/wmarkdown.png"], |
||||
"link" : "https://wmarkdown.k3y.pw/", |
||||
"text" : "WMarkDown" |
||||
}, { |
||||
"images" : ["https://wdictionaries.k3y.pw/images/wdictionaries.png"], |
||||
"link" : "https://wdictionaries.k3y.pw/", |
||||
"text" : "WDictionaries" |
||||
}] ]] |
||||
|
||||
Los siguientes proyectos usan este proyecto para llevar una gestión estadística de uso por páginas |
||||
Web. |
||||
|
||||
[[links_group [{ |
||||
"images" : ["https://wmarkdown.k3y.pw/images/wmarkdown.png"], |
||||
"link" : "https://wmarkdown.k3y.pw/", |
||||
"text" : "WMarkDown" |
||||
}, { |
||||
"images" : ["https://wdictionaries.k3y.pw/images/wdictionaries.png"], |
||||
"link" : "https://wdictionaries.k3y.pw/", |
||||
"text" : "WDictionaries" |
||||
}, { |
||||
"images" : ["https://kyman.k3y.pw/images/KyMAN.png"], |
||||
"link" : "https://kyman.k3y.pw/", |
||||
"text" : "KyMAN" |
||||
}, { |
||||
"images" : ["https://anp.k3y.pw/images/AnP.png"], |
||||
"link" : "https://anp.k3y.pw/", |
||||
"text" : "AnP" |
||||
}] ]] |
||||
|
||||
[[html_data { |
||||
"title" : "KStats - Proyectos", |
||||
"url" : "https://kstats.k3y.pw/es/", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "kstats,stats,statistics,kyman,wmd,wmarkdown,documentación,projects,proyectos", |
||||
"description" : "Proyectos con el KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "https://kstats.k3y.pw/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,45 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220402 |
||||
}]] |
||||
# Objetivos |
||||
|
||||
En esta sección se mostrarán los objetivos a llevar a cabo dentro de este proyecto. Todos ellos |
||||
serán realizados por KyMAN. |
||||
|
||||
- [X] Crear proyecto y base del mismo. |
||||
- [X] Crear base de datos con el procedimiento almacenado de inserción de registro. |
||||
- [X] Crear entorno servidor en PHP. Intentar capturar la URL desde el propio PHP y gestionar |
||||
sesión en entorno servidor. |
||||
- [X] Añadir campo de habilitado o deshabilitado a los Tokens. |
||||
- [X] Añadir campo de comprobación de URLs para evitar que cojan el Token para registrar sitios |
||||
no esperados. |
||||
- [X] Probar entorno CORS contra CSS. |
||||
- [X] Crear lado privado de los Tokens para coger los datos de los Tokens públicos. |
||||
- *Un Token privado puede tener más de un Token público.* |
||||
- *Un Token público no tiene porqué tener un Token privado.* |
||||
- [X] Añadir campo Observaciones a los Tokens. |
||||
- [X] Cambiar método de registro mediante ECMA/JS vía CORS. |
||||
- [-] Programar automatismo de Geolocalización de IPs. |
||||
- https://api.iplocation.net/ |
||||
- [-] Analizar los datos de las URLs de geolocalización añadidas a |
||||
https://kyman.k3y.pw/wlog/info.html#Geolocation. |
||||
- [X] Publicar versión funcional del proyecto. |
||||
- [-] Documentar. |
||||
- [-] Adaptar la documentación a que se genere en el servidor y mantener estadísticas de desarrollo |
||||
en el GitLab. |
||||
- [X] Arreglar Bug 2022040200. |
||||
|
||||
[[html_data { |
||||
"title" : "KStats - Objetivos", |
||||
"url" : "https://kstats.k3y.pw/es/targets.html", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220402, |
||||
"key_words" : "kstats,stats,statistics,kyman,wmd,wmarkdown,documentación,targets,objetivos", |
||||
"description" : "Objetivos del proyecto KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "https://kstats.k3y.pw/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,195 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320 |
||||
}]] |
||||
# Funcionamiento |
||||
|
||||
El funcionamiento del KStats está dividido en dos partes: cliente y servidor. Para empezar por la |
||||
parte más común, nos vamos a ir por la parte del lado cliente. Pero antes de empezar, es importante |
||||
mencionar que el entorno cliente es un entorno ECMAScript el cual ha de ser ejecutado para que |
||||
funcione sobre el lado servidor, y el lado servidor ha de estar activo. |
||||
|
||||
## Cliente |
||||
|
||||
El lado cliente se basa dos partes diferenciadas: en la creación del Token; y la instalación cliente |
||||
del mismo. |
||||
|
||||
> [[! important IMPORTANTE]]: El KStats funciona de dos formas diferentes cara el cliente: |
||||
registrando un histórico completo mediante ECMA/JS; y registrando accesos mediante petición URL. |
||||
|
||||
### Creación del Token |
||||
|
||||
Empezando por la creación del Token, nos encontramos en la base de datos, en caso de no tener acceso |
||||
por favor, pónganse en contacto con el administrador del sitio, y hay que ejecutar un procedimiento |
||||
almacenado llamado "token_create" el cual tiene los siguientes parámetros: |
||||
|
||||
- **$public (_entrada_)**: Parámetro de entrada que indica si el Token es público o no. Al estar |
||||
sobre el lado cliente éste ha de ser siempre "true". |
||||
- **$pattern (_entrada_)**: Parámetro de entrada que permite restringir los registros de URLs a un |
||||
patrón regular, el cual puede tener más de un radical, como por ejemplo el caso de la Web de KyMAN. |
||||
- **$remarks (_entrada_)**: Parámetro de entrada de texto libre con límite en 2048 caracteres que |
||||
sirve para describir el Token, finalidad, etc. Así como establecer notas, observaciones o cualquier |
||||
otro elemento textual que pertenezca al mismo. |
||||
- **$error (_salida_)**: Parámetro de salida que mostrará un código de error en formato numérico |
||||
entero donde cada bit representa lo siguiente según posición: |
||||
0. Excepción SQL. |
||||
1. El valor '$public' es nulo. |
||||
2. El valor '$pattern' es nulo. |
||||
3. El valor '$pattern' está vacío. |
||||
4. El valor '$remarks' es nulo. |
||||
5. El valor '$remarks' está vacío. |
||||
- **$id (_salida_)**: Parámetro de salida que retorna el ID del nuevo Token creado. |
||||
- **$token (_salida_)**: Parámetro de salida que retorna el nuevo Token creado. |
||||
|
||||
Ejemplos: |
||||
|
||||
```sql |
||||
|
||||
-- Para crear el Token de KSTats. |
||||
call token_create(true, '^https?\\:\\/{2}kstats\\.k3y\\.pw\\/?', 'Token for KStats project.', @error, @id, @token); |
||||
select @error, @id, @token; |
||||
|
||||
-- Para crear el Token de KyMAN y MiguelBST. |
||||
call token_create(true, '^https?\\:\\/{2}(kyman|m(iguel)?bst)\\.k3y\\.pw\\/?', 'Token for KyMAN|MBST project.', @error, @id, @token); |
||||
select @error, @id, @token; |
||||
|
||||
``` |
||||
|
||||
### Adjuntar KStats para ECMA/JS |
||||
|
||||
Una vez tenemos los Tokens creados, podemos ir al entorno cliente propiamente dicho donde hemos de |
||||
agregar en cada página Web donde queramos registrar los Stats el siguiente fragment HTML y ECMA. |
||||
|
||||
```html |
||||
|
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" src="https://kstats.k3y.pw/ecma/KStats.ecma.js" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
|
||||
<script> |
||||
|
||||
kstats = new KStats({url : "https://kstats.k3y.pw/api/SbfXgp4r3fAtuthpzXdZw2JTLKZqZFYzLhWTkQiQr4kYWsrcZvvsbKrHt/{session}/json/set"}); |
||||
|
||||
</script> |
||||
|
||||
``` |
||||
|
||||
La primera etiqueta adjunta a nuestra página Web el Script que gestiona el Script ECMA que nos hace |
||||
falta para poder ejecutar el KStats; mientras que el segundo crea el objeto KStats con la URL |
||||
concreta que identifica tu sitio Web dentro del KStats con su Token concreto. Es importante saber la |
||||
estructura de la URL de petición. |
||||
|
||||
Los parámetros de entrada que se le pueden dar a ese diccionario donde metemos la URL son los |
||||
siguientes: |
||||
|
||||
- **autostart**: Valor que determina si el objeto se inicia de forma automática (true) o se hace de |
||||
forma manual (false). Por defecto es true. |
||||
- **nulls**: Valor Booleano que determina si se admiten retornos nulos o no. Por defecto es false. |
||||
- **default_value**: Valor por defecto a retornar en caso de no tener opciones de valor. Por defecto |
||||
es null. |
||||
- **ajax_timeout**: Tiempo límite de ejecución de una petición asícrona AJAX (XMLHttpRequest) en |
||||
miliseguncos. Por defecto son 2000 milisegundos. |
||||
- **settings_overwrite**: Valor Booleano que determina si se sobreescriben los valores de la |
||||
configuración a la hora de añadirlos (true), en base a sus llaves, o no (false). Por defecto es false. |
||||
- **kstats_url**: URL por defecto a la cual atacar. Por defecto es |
||||
"https://kstats.k3y.pw/api/uCDY3brWxEJrJywm2sFcKo1d8oaUdmxTTrv3VGuhpyRDpPYXyKeHWeknh/{session}/ecma/set". |
||||
- **frames_per_second** o **fps**: Fotogramas por segundo o tasa de refrescos por segundo cara los |
||||
hilos. Por defecto son 1 fotograma por segundo. |
||||
- **milliseconds_per_connection**: Tiempo de espera entre una conexión y otra para actualizar el |
||||
estado actual del usuario en milisegundos. Por defecto son 2000. |
||||
- **session_cookie_name**: Nombre de llave de la Cookie que almacena la sesión del servidor de forma |
||||
cruzada. Por defecto es "kstats_session_id". |
||||
- **session_timeout**: Tiempo límite de inactividad de la sesión en milisegundos. Por defecto es de |
||||
60000. *Este valor no tiene efecto inicialmente*. |
||||
- **data_key**: Nombre de llave de variable por donde se enviarán los datos al servidor. Por defecto |
||||
es "kstats_data". **Tiene que ser el mismo que la del servidor.** |
||||
|
||||
### Registro por petición URL |
||||
|
||||
Este método permite hacer registro a partir de una llamada, tanto manual como automática, al |
||||
servidor. A continuación se presentarán ejemplos de llamadas automáticas: |
||||
|
||||
```html |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
|
||||
<!-- Llamada desde un ECMA --> |
||||
<script data-type="text/javascript" data-language="ECMAScript 2015" src="https://kstats.k3y.pw/api/SbfXgp4r3fAtuthpzXdZw2JTLKZqZFYzLhWTkQiQr4kYWsrcZvvsbKrHt/{session}/ecma/set" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
|
||||
<!-- Llamada desde un JS --> |
||||
<script data-type="text/javascript" data-language="JavaScript 1.8.5" src="https://kstats.k3y.pw/api/SbfXgp4r3fAtuthpzXdZw2JTLKZqZFYzLhWTkQiQr4kYWsrcZvvsbKrHt/{session}/js/set" data-crossorigin="anonymous" charset="utf-8"></script> |
||||
|
||||
<!-- Llamada desde un CSS --> |
||||
<link type="text/css" data-language="CSS3" rel="stylesheet" href="https://kstats.k3y.pw/api/SbfXgp4r3fAtuthpzXdZw2JTLKZqZFYzLhWTkQiQr4kYWsrcZvvsbKrHt/{session}/css/set" data-crossorigin="anonymous" charset="utf-8" /> |
||||
|
||||
</head> |
||||
<body> |
||||
|
||||
<!-- Llamada desde una imagen --> |
||||
<img src="https://kstats.k3y.pw/api/SbfXgp4r3fAtuthpzXdZw2JTLKZqZFYzLhWTkQiQr4kYWsrcZvvsbKrHt/{session}/img/set" alt="KStats" title="KStats" /> |
||||
<img src="https://kstats.k3y.pw/api/SbfXgp4r3fAtuthpzXdZw2JTLKZqZFYzLhWTkQiQr4kYWsrcZvvsbKrHt/{session}/image/set" alt="KStats" title="KStats" /> |
||||
|
||||
</body> |
||||
</html> |
||||
``` |
||||
|
||||
Y a continuación como se haría de forma manual desde HTML. |
||||
|
||||
```html |
||||
|
||||
<!-- Llamada mediante Link --> |
||||
<a href="https://kstats.k3y.pw/api/SbfXgp4r3fAtuthpzXdZw2JTLKZqZFYzLhWTkQiQr4kYWsrcZvvsbKrHt/{session}/text/set" target="_blank" title="KStats">KStats</a> |
||||
|
||||
<!-- Llamada mediante formulario --> |
||||
<form method="get" action="https://kstats.k3y.pw/api/SbfXgp4r3fAtuthpzXdZw2JTLKZqZFYzLhWTkQiQr4kYWsrcZvvsbKrHt/{session}/text/set"></form> |
||||
|
||||
``` |
||||
|
||||
### Estructura de la URL |
||||
|
||||
La estructura de la URL se compone de varias variables las cuales las encapsulamos a continuación entre llaves: |
||||
|
||||
```txt |
||||
https://{domain}/api/{token}/{session}/{response}/{action}/{id} |
||||
``` |
||||
|
||||
Cada una de estas variables indica lo siguiente: |
||||
|
||||
- **domain**: Parámetro obligatorio que indica el dominio donde se encuentra el sitio Web del |
||||
servidor KStats al que estamos atacando. |
||||
- **token**: Parámetro obligatorio que indica el Token a usar contra el servidor KStats. |
||||
- **session**: Parámetro obligatorio pero automático donde sólo hemos de indicar la variable, el |
||||
cual contendrá el ID de la sesión actual a partir de una Cookie local evitando que éstas se crucen |
||||
entre distintos dominios. |
||||
- **response**: Modo de respuesta tras la acción de registrar la petición. Estos modos son los |
||||
siguientes: |
||||
- **[[ignore js]]**: Retorna el Script KStats en formato JavaScript 1.8.5. |
||||
- **[[ignore ecma]]**: Retorna el Script KStats en formato ECMA 2015. |
||||
- **img** o **image**: Retorna una simple imagen de 1x1 de forma simbólica para no dar error |
||||
contra una etiqueta HTML IMG. |
||||
- **[[ignore css]]**: Retorna un contenido CSS para poder usar la etiqueta HTML LINK. |
||||
- **[[ignore json]]**: Retorna el resultado del proceso en formato JSON. |
||||
- **test**: Hace un retornos sobre un entorno de pruebas. |
||||
- **action**: Método o acción a ejecutar en el servidor. Dichos métodos son los siguientes: |
||||
- **set**: Establece un nuevo registro de conexión o actualiza uno ya existente. |
||||
- **id**: ID de registro actual o existente que se usará para determinar el tiempo de conexión en |
||||
esa página Web concreta. *No analizar tiempo de inactividad*. |
||||
|
||||
> [[! note NOTA]]: En caso de no tener ninguno de estos tipos de valor en la variable 'response', |
||||
éste retornará siempre un texto plano vacío. |
||||
|
||||
> [[! importante]]: El servidor ha de tener firma SSL para poder realizar la operación asíncrona |
||||
segura por defecto. |
||||
|
||||
[[html_data { |
||||
"title" : "KStats - Funcionamiento", |
||||
"url" : "https://kstats.k3y.pw/es/", |
||||
"author" : "KyMAN", |
||||
"since" : 20220320, |
||||
"version" : 20220320, |
||||
"key_words" : "kstats,stats,statistics,kyman,wmd,wmarkdown,documentación,funcionamiento", |
||||
"description" : "Funcionamiento del proyecto KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "https://kstats.k3y.pw/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
@ -0,0 +1,40 @@ |
||||
[[post_data { |
||||
"author" : "KyMAN", |
||||
"since" : 20220316, |
||||
"version" : 20220320 |
||||
}]] |
||||
# KStats |
||||
|
||||
Seleccione un idioma para acceder a la documentación del proyecto. |
||||
|
||||
[[links_group [{ |
||||
"images" : ["https://i.imgur.com/im1o0gc.png"], |
||||
"link" : "/es/", |
||||
"text" : "Español", |
||||
"self" : true |
||||
}] ]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/es/project.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/es/projects.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/es/bugs.w.md]] |
||||
|
||||
[[header_level 0]] |
||||
[[include /WMD/es/targets.w.md]] |
||||
|
||||
[[html_data { |
||||
"title" : "KStats - Idioma", |
||||
"url" : "https://kstats.k3y.pw/", |
||||
"author" : "KyMAN", |
||||
"since" : 20220316, |
||||
"version" : 20220320, |
||||
"key_words" : "kstats,stats,statistics,kyman,wmd,wmarkdown,documentación", |
||||
"description" : "Documentación del proyecto KStats.", |
||||
"project" : "KStats", |
||||
"logo" : "https://kstats.k3y.pw/images/KStats.png", |
||||
"language" : "es" |
||||
}]] |
Loading…
Reference in new issue