| Server IP : 188.114.97.3 / Your IP : 216.73.216.143 Web Server : Apache System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64 User : ( 3194769) PHP Version : 8.5.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /polana/ |
Upload File : |
<?php
/**
* TKLM POLANA POMIAR V2.0 — home.pl, PHP 8.0+
* Upload by FTP into website DOCROOT; visit /tklm-pomiar.php?setup=1.
* No shell, Composer, database or CRM required. Not a replacement for Umami.
* Does not store IP, email, phone numbers, form fields, full referrer URLs.
*/
declare(strict_types=1);
const TKLM_POMIAR_VERSION = '2.0.0';
const TKLM_POMIAR_SETUP_KEY = 'PbJw_4_rIv7-OO23q-t_lpTfoscx6w';
const TKLM_POMIAR_API_KEY = 'CMevRuyNfJEKw85qesR1qerOMUle4axjuIKRqTxL';
const TKLM_POMIAR_ALLOWED_HOSTS = ['mojapolanasmakow.pl', 'www.mojapolanasmakow.pl', 'localhost', '127.0.0.1'];
// OPTIONAL: set these to your actual Umami settings. Never guess a website ID.
const TKLM_POMIAR_UMAMI_SCRIPT_URL = ''; // e.g. 'https://your-umami-domain/script.js'
const TKLM_POMIAR_UMAMI_WEBSITE_ID = ''; // exact UUID from Umami panel
const TKLM_POMIAR_RETENTION_DAYS = 90;
function tklm_pm_warsaw_date(int $ts): string {
return (new DateTimeImmutable('@'.$ts))->setTimezone(new DateTimeZone('Europe/Warsaw'))->format('Y-m-d');
}
function tklm_pm_warsaw_day_offset(int $offset): string {
return (new DateTimeImmutable('today',new DateTimeZone('Europe/Warsaw')))->modify('-'.(int)$offset.' days')->format('Y-m-d');
}
function tklm_pm_private_dir(): string {
return __DIR__ . '/.tklm-pomiar-prywatne';
}
function tklm_pm_guard(): string {
return "<?php http_response_code(404); exit; ?>\n";
}
function tklm_pm_ensure_dir(): bool {
$dir = tklm_pm_private_dir();
if (!is_dir($dir) && !@mkdir($dir, 0700, true) && !is_dir($dir)) return false;
$htaccess = $dir . '/.htaccess';
if (!file_exists($htaccess)) @file_put_contents($htaccess, "Require all denied\nDeny from all\nOptions -Indexes\n");
$index = $dir . '/index.php';
if (!file_exists($index)) @file_put_contents($index, tklm_pm_guard());
return is_writable($dir);
}
function tklm_pm_normalize_path(string $path): string {
$path = (string)(parse_url($path, PHP_URL_PATH) ?: '/');
if ($path === '' || $path[0] !== '/') $path = '/';
$path = preg_replace('~/{2,}~', '/', $path) ?? '/';
$path = preg_replace('/[^a-zA-Z0-9_\-\/%.]/', '', $path) ?? '/';
return substr($path, 0, 180) ?: '/';
}
function tklm_pm_is_private_path(string $p): bool {
return (bool)preg_match('~(^|/)(admin|api|panel|wp-admin|tklm-pomiar\.php|\.tklm-pomiar-prywatne)(/|$|\?)~i', $p);
}
function tklm_pm_valid_event(string $event, bool $backend): bool {
$frontend = ['pageview', 'session_start', 'menu_view', 'reservation_view', 'reservation_open', 'phone_click', 'email_click', 'external_booking_click'];
$server = ['reservation_submitted', 'reservation_confirmed', 'newsletter_signup', 'contact_form_submitted'];
return in_array($event, $backend ? $server : $frontend, true);
}
function tklm_pm_save(string $event, string $path, string $session = '', string $ref = '', string $device = '', bool $backend = false): bool {
if (!tklm_pm_valid_event($event, $backend)) return false;
$path = tklm_pm_normalize_path($path);
if (tklm_pm_is_private_path($path)) return false;
if (!tklm_pm_ensure_dir()) return false;
$ts = time();
$day = tklm_pm_warsaw_date($ts);
$file = tklm_pm_private_dir() . '/' . $day . '.php';
$session = preg_match('/^[a-f0-9]{32}$/', $session) ? $session : '';
// daily rotating pseudo-ID: only used to count browser tab sessions per day
$sidHash = $session === '' ? '' : substr(hash_hmac('sha256', $day . '|' . $session, TKLM_POMIAR_API_KEY), 0, 24);
$ref = strtolower(substr(preg_replace('/[^a-z0-9.\-]/i', '', $ref) ?? '', 0, 100));
$device = in_array($device, ['mobile', 'tablet', 'desktop'], true) ? $device : 'unknown';
$row = ['ts' => gmdate('c', $ts), 'event' => $event, 'path' => $path,
'session' => $sidHash, 'ref_domain' => $ref, 'device' => $device,
'kind' => $backend ? 'backend' : 'browser'];
$json = json_encode($row, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if ($json === false) return false;
$h = @fopen($file, 'c+');
if ($h === false) return false;
$ok = false;
if (flock($h, LOCK_EX)) {
$sz = fstat($h)['size'] ?? 0;
if ($sz <= 20 * 1024 * 1024) {
if ($sz === 0) fwrite($h, tklm_pm_guard());
fseek($h, 0, SEEK_END);
$ok = fwrite($h, $json . "\n") === strlen($json) + 1;
}
fflush($h);
flock($h, LOCK_UN);
}
fclose($h);
if (random_int(1, 400) === 1) tklm_pm_cleanup();
return $ok;
}
function tklm_pm_cleanup(): void {
$threshold = tklm_pm_warsaw_day_offset(TKLM_POMIAR_RETENTION_DAYS);
foreach (glob(tklm_pm_private_dir() . '/????-??-??.php') ?: [] as $path) {
if (preg_match('/(\d{4}-\d{2}-\d{2})\.php$/', $path, $m) && $m[1] < $threshold) @unlink($path);
}
}
/** Call ONLY after a successful DB write / transaction COMMIT in the website's PHP code. */
function tklm_pomiar_backend_event(string $event, string $path = '/rezerwacja'): bool {
return tklm_pm_save($event, $path, '', '', '', true);
}
function tklm_pm_host_ok(): bool {
$h = strtolower((string)($_SERVER['HTTP_HOST'] ?? ''));
$h = explode(':', $h)[0];
return in_array($h, TKLM_POMIAR_ALLOWED_HOSTS, true);
}
function tklm_pm_same_site_post(): bool {
$origin = trim((string)($_SERVER['HTTP_ORIGIN'] ?? ''));
$referer = trim((string)($_SERVER['HTTP_REFERER'] ?? ''));
if ($origin === '' && $referer === '') return false;
foreach ([$origin, $referer] as $url) {
if ($url === '') continue;
$host = strtolower((string)(parse_url($url, PHP_URL_HOST) ?: ''));
if ($host === '' || !in_array($host, TKLM_POMIAR_ALLOWED_HOSTS, true)) return false;
}
return true;
}
function tklm_pm_fail(int $code = 404): void { http_response_code($code); exit; }
function tklm_pm_headers(string $type): void {
header('Content-Type: ' . $type);
header('X-Content-Type-Options: nosniff');
header('X-Robots-Tag: noindex, nofollow, noarchive');
header('Referrer-Policy: no-referrer');
}
function tklm_pm_h(string $s): string {return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');}
function tklm_pm_get_data(int $days): array {
$days = max(1, min(90, $days));
$counts = ['days' => $days, 'pageviews' => 0, 'sessions' => 0, 'events' => [], 'pages' => [],
'referrers' => [], 'devices' => [], 'daily' => [], 'range_start_pl' => tklm_pm_warsaw_day_offset($days - 1), 'range_end_pl' => tklm_pm_warsaw_day_offset(0), 'date_timezone' => 'Europe/Warsaw'];
$globalSessions = [];
for ($i = $days - 1; $i >= 0; --$i) {
$date = tklm_pm_warsaw_day_offset($i);
$file = tklm_pm_private_dir() . '/' . $date . '.php';
$d = ['date' => $date, 'pageviews' => 0, 'sessions' => 0, 'events' => []];
$sessions = [];
if (is_file($file) && ($fh = @fopen($file, 'r')) !== false) {
fgets($fh); // PHP exit-guard header
$max = 150000; // safety cap
while (($line = fgets($fh)) !== false && --$max > 0) {
$v = json_decode($line, true);
if (!is_array($v) || !isset($v['event'], $v['path'])) continue;
$evt = (string)$v['event']; $path = (string)$v['path'];
$d['events'][$evt] = ($d['events'][$evt] ?? 0) + 1;
$counts['events'][$evt] = ($counts['events'][$evt] ?? 0) + 1;
if ($evt === 'pageview') {
$d['pageviews']++;
$counts['pageviews']++;
$counts['pages'][$path] = ($counts['pages'][$path] ?? 0) + 1;
$ref = (string)($v['ref_domain'] ?? '');
if ($ref !== '') $counts['referrers'][$ref] = ($counts['referrers'][$ref] ?? 0) + 1;
$dev = (string)($v['device'] ?? 'unknown');
$counts['devices'][$dev] = ($counts['devices'][$dev] ?? 0) + 1;
}
if ($evt === 'session_start' && !empty($v['session'])) $sessions[$v['session']] = true;
}
fclose($fh);
}
$d['sessions'] = count($sessions);
$counts['sessions'] += $d['sessions']; // sessions per day, NOT unique users
$counts['daily'][] = $d;
}
foreach (['pages', 'events', 'referrers', 'devices'] as $key) arsort($counts[$key]);
return $counts;
}
function tklm_pm_js(): void {
tklm_pm_headers('application/javascript; charset=UTF-8');
header('Cache-Control: public, max-age=300');
$endpoint = (string)($_SERVER['SCRIPT_NAME'] ?? '/tklm-pomiar.php');
$uri = json_encode($endpoint . '?collect=1', JSON_UNESCAPED_SLASHES);
$umamiURL = json_encode(TKLM_POMIAR_UMAMI_SCRIPT_URL, JSON_UNESCAPED_SLASHES);
$umamiId = json_encode(TKLM_POMIAR_UMAMI_WEBSITE_ID, JSON_UNESCAPED_SLASHES);
$js = <<<'JS'
(function(){
'use strict';
if(window.__TKLM_POLANA_POMIAR_V2__) return;
window.__TKLM_POLANA_POMIAR_V2__=true;
var endpoint=__ENDPOINT__, umamiUrl=__UMAMI_URL__, umamiId=__UMAMI_ID__;
var path=window.location.pathname || '/';
if(/^\/(admin|api|panel|wp-admin)(\/|$)/i.test(path)) return;
function randomId(){
var a=new Uint8Array(16); if(!window.crypto||!window.crypto.getRandomValues)return null;
window.crypto.getRandomValues(a); return Array.from(a).map(function(x){return x.toString(16).padStart(2,'0')}).join('');
}
var dt=new Date(),day=[dt.getFullYear(),String(dt.getMonth()+1).padStart(2,'0'),String(dt.getDate()).padStart(2,'0')].join('-');
var sid='',fresh=false;
try {
sid=sessionStorage.getItem('tklm_pm_sid')||'';
if(!/^[a-f0-9]{32}$/.test(sid)){sid=randomId()||'';if(sid)sessionStorage.setItem('tklm_pm_sid',sid)}
var key='tklm_pm_started_'+day;
if(!sessionStorage.getItem(key)){fresh=true;sessionStorage.setItem(key,'1')}
} catch(e){sid=randomId()||'';fresh=true}
function refDomain(){try{return document.referrer?new URL(document.referrer).hostname:''}catch(e){return ''}}
function device(){var w=window.innerWidth||0;return w<700?'mobile':(w<1024?'tablet':'desktop')}
function send(event, overridePath){
var payload={event:event,path:overridePath||window.location.pathname||'/',sid:sid,ref_domain:refDomain(),device:device()};
var body=JSON.stringify(payload);
if(navigator.sendBeacon){
try{if(navigator.sendBeacon(endpoint,new Blob([body],{type:'text/plain'})))return}catch(e){}
}
try{fetch(endpoint,{method:'POST',credentials:'omit',body:body,headers:{'Content-Type':'text/plain'},keepalive:true,mode:'same-origin'}).catch(function(){})}catch(e){}
}
function umamiEvent(name){try{if(window.umami&&typeof window.umami.track==='function')window.umami.track(name)}catch(e){}}
function customEvent(name){
// Proven conversions must come from PHP backend, NEVER from a button click.
if(!/^(menu_view|reservation_view|reservation_open|phone_click|email_click|external_booking_click)$/.test(name))return false;
send(name);umamiEvent(name);return true;
}
window.TKLMPomiar={event:customEvent,version:'2.0.0'};
if(umamiUrl && umamiId && /^https:\/\//i.test(umamiUrl)){
var installed=!!document.querySelector('script[data-website-id]');
if(!installed){
var s=document.createElement('script');s.src=umamiUrl;s.defer=true;
s.setAttribute('data-website-id',umamiId);document.head.appendChild(s);
}
}
if(fresh) send('session_start');
send('pageview');
if(/^\/menu\/?$/i.test(path))customEvent('menu_view');
if(/^\/rezerwacja\/?$/i.test(path))customEvent('reservation_view');
document.addEventListener('click',function(e){
var a=e.target&&e.target.closest?e.target.closest('a[href]'):null;if(!a)return;
var href=a.getAttribute('href')||'';
if(/^tel:/i.test(href)){customEvent('phone_click');return}
if(/^mailto:/i.test(href)){customEvent('email_click');return}
try {var u=new URL(href,location.href);
if(u.origin===location.origin && /^\/rezerwacja\/?$/i.test(u.pathname))customEvent('reservation_open');
}catch(x){}
},true);
})();
JS;
echo str_replace(['__ENDPOINT__','__UMAMI_URL__','__UMAMI_ID__'], [$uri, $umamiURL, $umamiId], $js);
}
function tklm_pm_collect(): void {
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') tklm_pm_fail(405);
if (!tklm_pm_same_site_post()) tklm_pm_fail(403);
if ((int)($_SERVER['CONTENT_LENGTH'] ?? 0) > 3072) tklm_pm_fail(413);
$input = file_get_contents('php://input', false, null, 0, 3073);
if (!is_string($input) || strlen($input) > 3072) tklm_pm_fail(413);
$data = json_decode($input, true);
if (!is_array($data)) tklm_pm_fail(400);
$event = (string)($data['event'] ?? '');
if (!tklm_pm_valid_event($event, false)) tklm_pm_fail(422);
$path = tklm_pm_normalize_path((string)($data['path'] ?? '/'));
if (tklm_pm_is_private_path($path)) tklm_pm_fail(403);
$ok = tklm_pm_save($event, $path, (string)($data['sid'] ?? ''),
(string)($data['ref_domain'] ?? ''), (string)($data['device'] ?? ''));
header('Cache-Control: no-store');
http_response_code($ok ? 204 : 503);
}
function tklm_pm_api_auth(): bool {
return hash_equals(TKLM_POMIAR_API_KEY, (string)($_SERVER['HTTP_X_TKLM_API_KEY'] ?? ''));
}
function tklm_pm_setup_auth(): bool {
return hash_equals(TKLM_POMIAR_SETUP_KEY, (string)($_POST['key'] ?? ''));
}
function tklm_pm_candidates(): array {
$root = __DIR__;
$files = ['index.php', 'footer.php', 'includes/footer.php', 'partials/footer.php', 'templates/footer.php',
'templates/layout.php', 'views/footer.php', 'inc/footer.php', 'layout.php', 'app/views/layout.php'];
$out=[];
foreach ($files as $rel) {
$file=$root.'/'.$rel;
if (!is_file($file) || filesize($file)>600000 || !is_readable($file)) continue;
$data=@file_get_contents($file); if (!is_string($data) || str_contains($data, 'TKLM_POMIAR_BEGIN')) continue;
if (tklm_pm_patch_markup($data) !== null) $out[]=$rel;
}
return $out;
}
function tklm_pm_snippet(): string {
return "<!-- TKLM_POMIAR_BEGIN -->\n<script defer src=\"/tklm-pomiar.php?js=1\"></script>\n<!-- TKLM_POMIAR_END -->\n";
}
function tklm_pm_patch_markup(string $content): ?string {
// Modify ONLY the HTML outside PHP code. Never inject into a PHP string or echo.
if (str_contains($content, 'TKLM_POMIAR_BEGIN')) return null;
$tokens = token_get_all($content);
$matches = 0; $result = '';
foreach ($tokens as $tok) {
if (is_array($tok) && $tok[0] === T_INLINE_HTML) {
$chunk = $tok[1];
$n = preg_match_all('~</body\s*>~i', $chunk);
if ($n) {
$matches += $n;
$chunk = preg_replace('~</body\s*>~i', tklm_pm_snippet().'$0', $chunk, 1) ?? $chunk;
}
$result .= $chunk;
} else $result .= is_array($tok) ? $tok[1] : $tok;
}
return $matches === 1 ? $result : null;
}
function tklm_pm_setup_install(string $rel): string {
if (!in_array($rel, tklm_pm_candidates(), true)) return 'Odmowa: wskazany plik nie ma bezpiecznego, jednoznacznego znacznika </body> w HTML.';
$state=tklm_pm_private_dir().'/install-state.php';
if (is_file($state)) return 'Odmowa: instalacja jest już zarejestrowana. Najpierw sprawdź status lub wykonaj rollback.';
if (!tklm_pm_ensure_dir()) return 'BŁĄD: nie mogę utworzyć prywatnego katalogu danych.';
$file=__DIR__.'/'.$rel;
$original=@file_get_contents($file);if (!is_string($original))return 'BŁĄD: odczyt pliku.';
$new=tklm_pm_patch_markup($original);if ($new===null)return 'Odmowa: nie można bezpiecznie wstawić kodu.';
$backup='backup_'.bin2hex(random_bytes(8)).'.php';
if (@file_put_contents(tklm_pm_private_dir().'/'.$backup,tklm_pm_guard().$original, LOCK_EX)===false) return 'BŁĄD: nie można zapisać backupu.';
$stateRow=['file'=>$rel,'backup'=>$backup,'before'=>hash('sha256',$original),'after'=>hash('sha256',$new),'installed_at'=>gmdate('c')];
$stateBytes=tklm_pm_guard().json_encode($stateRow,JSON_UNESCAPED_SLASHES);
if (@file_put_contents($state,$stateBytes,LOCK_EX)===false)return 'BŁĄD: nie można zapisać informacji do rollbacku. Niczego nie zmieniono.';
$mode=fileperms($file)&0777;
$temp=dirname($file).'/.tklm-temp-'.bin2hex(random_bytes(5)).'.php';
if (@file_put_contents($temp,$new,LOCK_EX)===false){@unlink($state);return 'BŁĄD: brak możliwości zapisu pliku tymczasowego.';}
@chmod($temp,$mode);
if (!@rename($temp,$file)) {@unlink($temp);@unlink($state);return 'BŁĄD: nie można podmienić pliku źródłowego.';}
if (hash_file('sha256',$file)!==$stateRow['after']) return 'UWAGA: zapis pliku wymaga ręcznej weryfikacji. Backup jest dostępny.';
return 'OK: zapisano backup i dodano tracker do '.$rel.'. Otwórz stronę i sprawdź, czy zbiera dane.';
}
function tklm_pm_state(): ?array {
$f=tklm_pm_private_dir().'/install-state.php';if (!is_file($f))return null;
$data=@file_get_contents($f); if (!is_string($data))return null;
$d=json_decode(substr($data,strlen(tklm_pm_guard())),true);
return is_array($d)?$d:null;
}
function tklm_pm_setup_rollback(): string {
$state=tklm_pm_state();if (!$state)return 'Nie znaleziono instalacji wykonanej przez instalator.';
$file=__DIR__.'/'.($state['file']??'');
$backup=tklm_pm_private_dir().'/'.basename((string)($state['backup']??''));
if (!is_file($file)||!is_file($backup))return 'BŁĄD: brakuje pliku strony lub backupu.';
if (hash_file('sha256',$file)!==($state['after']??''))return 'Odmowa rollbacku: plik był edytowany po instalacji. Nie nadpisuję nowszych zmian.';
$raw=@file_get_contents($backup);if(!is_string($raw))return 'BŁĄD: backup nieczytelny.';
$original=substr($raw,strlen(tklm_pm_guard()));
if (hash('sha256',$original)!==($state['before']??''))return 'Odmowa: suma kontrolna backupu się nie zgadza.';
$mode=fileperms($file)&0777;
$tmp=dirname($file).'/.tklm-restore-'.bin2hex(random_bytes(5)).'.php';
if (@file_put_contents($tmp,$original,LOCK_EX)===false)return 'BŁĄD: nie można zapisać tymczasowego pliku.';
@chmod($tmp,$mode);
if (!@rename($tmp,$file)){@unlink($tmp);return 'BŁĄD: nie udało się przywrócić pliku.';}
if(hash_file('sha256',$file)!==($state['before']??''))return 'UWAGA: sprawdź przywrócony plik.';
@unlink(tklm_pm_private_dir().'/install-state.php');
return 'OK: przywrócono oryginalny '.$state['file'].'. Dane pomiarowe pozostają zachowane.';
}
function tklm_pm_setup_page(): void {
tklm_pm_headers('text/html; charset=UTF-8');
header('Cache-Control: no-store, no-cache, must-revalidate');
$action=(string)($_POST['action']??'');$message='';$authed=false;
if (($_SERVER['REQUEST_METHOD']??'')==='POST'){
$authed=tklm_pm_setup_auth();
if (!$authed) $message='Błędne hasło instalatora.';
elseif ($action==='install') $message=tklm_pm_setup_install((string)($_POST['target']??''));
elseif ($action==='rollback') $message=tklm_pm_setup_rollback();
elseif ($action==='status') $message='Diagnostyka odczytana poniżej.';
}
$state=tklm_pm_state();$candidates=tklm_pm_candidates();
$data=$authed?tklm_pm_get_data(30):null;
$storage=tklm_pm_ensure_dir()?'OK':'BRAK ZAPISU';
echo '<!doctype html><html lang="pl"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>TKLM Pomiar · home.pl</title><style>body{font:16px/1.5 system-ui;background:#141414;color:#eee;margin:0;padding:28px}main{max-width:820px;margin:auto}section{border:1px solid #444;padding:18px;border-radius:12px;margin:16px 0}input,select,button{font:inherit;padding:10px;margin:6px 0;border-radius:7px}input,select{background:#252525;color:#fff;border:1px solid #666;max-width:95%}button{cursor:pointer;background:#d7963a;border:0;font-weight:bold}code{overflow-wrap:anywhere}p{margin:8px 0}.sub{color:#aaa}.msg{border-left:4px solid #dfa44a;padding:12px;background:#26201a}table{border-collapse:collapse}td,th{padding:6px 18px 6px 0;border-bottom:1px solid #555;text-align:left}</style><main><h1>TKLM · Pomiar V2 / home.pl</h1><p class="sub">Działa na serwerze strony, bez SSH i bez CRM. Domeny: mojapolanasmakow.pl</p>';
if($message!=='')echo '<p class="msg">'.tklm_pm_h($message).'</p>';
echo '<section><h2>Instalacja i diagnostyka</h2><p>Wersja PHP: '.tklm_pm_h(PHP_VERSION).' · katalog danych: '.tklm_pm_h($storage).' · status wpięcia: '.($state?'TAK':'NIE (lub integracja ręczna)').'</p>';
if($state)echo '<p>Automatycznie wpięty plik: <code>'.tklm_pm_h((string)$state['file']).'</code>, UTC '.tklm_pm_h((string)$state['installed_at']).'</p>';
echo '<form method="post"><label>Hasło instalatora<br><input type="password" name="key" autocomplete="off" required></label><br>';
if(!$state && count($candidates)>0){echo '<label>Plik strony z bezpiecznym </body><br><select name="target">';foreach($candidates as $item)echo '<option value="'.tklm_pm_h($item).'">'.tklm_pm_h($item).'</option>';echo '</select></label><br><button type="submit" name="action" value="install">Zrób backup i włącz pomiar</button> ';}
if($state)echo '<button type="submit" name="action" value="rollback">Rollback pliku strony</button> ';
echo '<button type="submit" name="action" value="status">Sprawdź ostatnie 30 dni</button></form>';
if(count($candidates)===0 && !$state) echo '<p>Nie znalazłem bezpiecznego miejsca do automatycznej zmiany. Dodaj do wspólnego szablonu strony, przed <code></body></code>:</p><p><code>'.tklm_pm_h('<script defer src="/tklm-pomiar.php?js=1"></script>').'</code></p>';
echo '<p>Rezerwacje z potwierdzonym zapisem wymagają wywołania funkcji PHP po udanym COMMIT (opis w instrukcji). Samo kliknięcie „Wyślij” nie jest konwersją.</p></section>';
if($authed && is_array($data)) {
echo '<section><h2>Pomiar z ostatnich 30 dni (własny licznik strony)</h2><p>Odsłony: <b>'.(int)$data['pageviews'].'</b> · Sesje dzienne: <b>'.(int)$data['sessions'].'</b></p><table><tr><th>Zdarzenie</th><th>Liczba</th></tr>';
foreach($data['events'] as $e=>$n)echo '<tr><td>'.tklm_pm_h((string)$e).'</td><td>'.(int)$n.'</td></tr>';
echo '</table><p class="sub">To niezależny pomiar, a nie dane Umami. „Sesje” oznaczają sesje kart przeglądarki, nie unikalnych użytkowników.</p></section>';
}
echo '<section><h2>Co dalej z CRM?</h2><p>Po pojawieniu się odsłon CRM może pobierać podsumowania przez <code>GET /tklm-pomiar.php?export=1&days=30</code> z nagłówkiem <code>X-TKLM-API-Key</code>. Klucz podany jest tylko w prywatnej instrukcji. Sam plik nie potrzebuje połączenia z CRM.</p></section>';
echo '</main></html>';
}
function tklm_pm_entry(): void {
if (!tklm_pm_host_ok()) tklm_pm_fail(404);
if (isset($_GET['js'])) { if (($_SERVER['REQUEST_METHOD']??'')!=='GET') tklm_pm_fail(405); tklm_pm_js(); return; }
if (isset($_GET['collect'])) {tklm_pm_collect();return;}
if (isset($_GET['export'])) {
if (($_SERVER['REQUEST_METHOD']??'')!=='GET')tklm_pm_fail(405);
if(!tklm_pm_api_auth())tklm_pm_fail(403);
tklm_pm_headers('application/json; charset=UTF-8');header('Cache-Control: no-store');
echo json_encode(['version'=>TKLM_POMIAR_VERSION,'domain'=>'mojapolanasmakow.pl','generated_utc'=>gmdate('c'),
'methodology'=>'PHP site tracker. Anonymous pageviews; daily tab sessions; no unique users.',
'data'=>tklm_pm_get_data((int)($_GET['days']??30))], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
return;
}
if (isset($_GET['setup'])) {tklm_pm_setup_page();return;}
tklm_pm_fail(404);
}
if (isset($_SERVER['SCRIPT_FILENAME']) && realpath((string)$_SERVER['SCRIPT_FILENAME']) === __FILE__) {
tklm_pm_entry();
}