fix: Migrating project to the new Gitea Host.

main
KyMAN 4 months ago
parent ef348f1979
commit a7ea9227cf
  1. 6
      .gitignore
  2. 183
      HTML/base.kstats.html
  3. 1
      JSON/html.files.json
  4. 447
      MySQL/KStats.my.sql
  5. 302
      PHP/KStats.php
  6. 8
      PHP/include.php
  7. 7
      Public/.htaccess
  8. 5
      Public/api/index.php
  9. 247
      Public/ecma/KStats.ecma.js
  10. 4
      Public/git_update.php
  11. BIN
      Public/images/min.png
  12. 33
      Public/tests/cookies.html
  13. 23
      Public/tests/sessions.php
  14. 29
      Public/tests/test.html
  15. 6
      Public/wmd.php
  16. 21
      Public/wmd_scripts.php
  17. 24
      WMD/dev/ECMAScript/index.w.md
  18. 36
      WMD/dev/PHP/index.w.md
  19. 23
      WMD/dev/Public/api/index.php.w.md
  20. 268
      WMD/dev/Public/ecma/KStats.ecma.js.w.md
  21. 23
      WMD/dev/Public/git_update.php.w.md
  22. 23
      WMD/dev/Public/tests/sessions.php.w.md
  23. 23
      WMD/dev/Public/wmd.php.w.md
  24. 23
      WMD/dev/Public/wmd_scripts.php.w.md
  25. 0
      WMD/dev/index.w.md
  26. 52
      WMD/es/bugs.w.md
  27. 37
      WMD/es/index.w.md
  28. 24
      WMD/es/project.w.md
  29. 54
      WMD/es/projects.w.md
  30. 45
      WMD/es/targets.w.md
  31. 195
      WMD/es/work.w.md
  32. 40
      WMD/index.w.md

6
.gitignore vendored

@ -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");

Binary file not shown.

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…
Cancel
Save