<?php
/*
OC3 Analytics Tracker - coste externo cero.
Instalar en la raíz del portal como: /oc3-analytics/tracker.php
No guarda IPs en claro. No usa cookies. No llama a servicios externos.
*/
declare(strict_types=1);

$PORTAL_SLUG = 'mi-abogado-pro';
$PORTAL_NAME = 'mi Abogado PRO';

function oc3_headers_common(): void {
    header('X-Content-Type-Options: nosniff');
    header('Referrer-Policy: strict-origin-when-cross-origin');
    header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
}

function oc3_safe_str($v, int $max = 300): string {
    if (!is_string($v)) return '';
    $v = trim(preg_replace('/[\x00-\x1F\x7F]/u', ' ', $v));
    if (function_exists('mb_substr')) return mb_substr($v, 0, $max, 'UTF-8');
    return substr($v, 0, $max);
}

function oc3_secret(): string {
    $file = __DIR__ . '/config_secret.php';
    if (!file_exists($file)) {
        $secret = bin2hex(random_bytes(32));
        @file_put_contents($file, "<?php\nreturn '" . $secret . "';\n", LOCK_EX);
    }
    $secret = @include $file;
    if (!is_string($secret) || strlen($secret) < 32) {
        $secret = hash('sha256', __DIR__ . '|' . ($_SERVER['HTTP_HOST'] ?? 'host') . '|fallback');
    }
    return $secret;
}

function oc3_same_origin_ok(): bool {
    $host = strtolower($_SERVER['HTTP_HOST'] ?? '');
    $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
    if ($origin === '') return true;
    $ohost = strtolower((string)parse_url($origin, PHP_URL_HOST));
    return $ohost === '' || $ohost === preg_replace('/:\d+$/', '', $host) || $ohost === $host;
}

if (isset($_GET['js'])) {
    oc3_headers_common();
    header('Content-Type: application/javascript; charset=utf-8');
    $endpoint = './tracker.php';
    ?>
(function(){
  "use strict";
  var endpoint = (document.currentScript && document.currentScript.src)
    ? document.currentScript.src.replace(/\?js=1.*$/, "")
    : "<?php echo $endpoint; ?>";
  var portal = "<?php echo addslashes($PORTAL_SLUG); ?>";
  var lastPath = "";
  function sid(){
    try {
      var k = "oc3_session_id";
      var v = sessionStorage.getItem(k);
      if (!v) {
        v = Date.now().toString(36) + "-" + Math.random().toString(36).slice(2);
        sessionStorage.setItem(k, v);
      }
      return v;
    } catch(e) { return ""; }
  }
  function clean(s, n){
    s = (s || "").toString().replace(/\s+/g, " ").trim();
    return s.slice(0, n || 220);
  }
  function send(payload){
    payload.portal = portal;
    payload.ts_client = new Date().toISOString();
    payload.path = location.pathname + location.search;
    payload.title = clean(document.title, 180);
    payload.referrer = clean(document.referrer, 300);
    payload.sid = sid();
    var body = JSON.stringify(payload);
    try {
      if (navigator.sendBeacon) {
        var blob = new Blob([body], {type: "application/json"});
        navigator.sendBeacon(endpoint, blob);
        return;
      }
    } catch(e) {}
    try {
      fetch(endpoint, {method:"POST", headers:{"Content-Type":"application/json"}, body:body, keepalive:true, credentials:"same-origin"});
    } catch(e) {}
  }
  function pageview(reason){
    var p = location.pathname + location.search;
    if (p === lastPath && reason !== "load") return;
    lastPath = p;
    send({event:"pageview", reason:reason || "load", screen:(screen.width+"x"+screen.height)});
  }
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", function(){ pageview("load"); });
  } else {
    pageview("load");
  }
  document.addEventListener("click", function(ev){
    var el = ev.target && ev.target.closest ? ev.target.closest("a,button,[role='button'],input[type='submit'],input[type='button'],.btn") : null;
    if (!el) return;
    send({
      event:"click",
      tag: clean(el.tagName, 30),
      id: clean(el.id, 80),
      classes: clean(el.className && el.className.toString ? el.className.toString() : "", 160),
      text: clean(el.innerText || el.value || el.getAttribute("aria-label") || el.getAttribute("title") || "", 160),
      href: clean(el.href || el.getAttribute("href") || "", 300)
    });
  }, true);
  var oldPush = history.pushState;
  var oldReplace = history.replaceState;
  history.pushState = function(){ oldPush.apply(history, arguments); setTimeout(function(){ pageview("pushState"); }, 0); };
  history.replaceState = function(){ oldReplace.apply(history, arguments); setTimeout(function(){ pageview("replaceState"); }, 0); };
  window.addEventListener("popstate", function(){ setTimeout(function(){ pageview("popstate"); }, 0); });
})();
<?php
    exit;
}

oc3_headers_common();

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(204);
    exit;
}

if (!oc3_same_origin_ok()) {
    http_response_code(403);
    exit;
}

$raw = file_get_contents('php://input', false, null, 0, 8192);
if (!is_string($raw) || $raw === '' || strlen($raw) > 8192) {
    http_response_code(400);
    exit;
}

$data = json_decode($raw, true);
if (!is_array($data)) {
    http_response_code(400);
    exit;
}

$event = oc3_safe_str($data['event'] ?? '', 30);
if (!in_array($event, ['pageview', 'click'], true)) {
    http_response_code(204);
    exit;
}

$secret = oc3_secret();
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$day = gmdate('Y-m-d');

$ref = oc3_safe_str($data['referrer'] ?? '', 300);
$refHost = '';
if ($ref !== '') {
    $refHost = oc3_safe_str((string)parse_url($ref, PHP_URL_HOST), 120);
}

$row = [
    'ts' => gmdate('c'),
    'portal' => $PORTAL_SLUG,
    'portal_name' => $PORTAL_NAME,
    'event' => $event,
    'host' => oc3_safe_str($_SERVER['HTTP_HOST'] ?? '', 160),
    'path' => oc3_safe_str($data['path'] ?? ($_SERVER['REQUEST_URI'] ?? ''), 500),
    'title' => oc3_safe_str($data['title'] ?? '', 220),
    'referrer_host' => $refHost,
    'reason' => oc3_safe_str($data['reason'] ?? '', 30),
    'tag' => oc3_safe_str($data['tag'] ?? '', 30),
    'element_id' => oc3_safe_str($data['id'] ?? '', 80),
    'classes' => oc3_safe_str($data['classes'] ?? '', 160),
    'text' => oc3_safe_str($data['text'] ?? '', 160),
    'href' => oc3_safe_str($data['href'] ?? '', 500),
    'screen' => oc3_safe_str($data['screen'] ?? '', 40),
    'visitor_hash' => hash_hmac('sha256', $ip . '|' . $ua . '|' . $day, $secret),
    'session_hash' => hash_hmac('sha256', oc3_safe_str($data['sid'] ?? '', 120) . '|' . $ip . '|' . $day, $secret),
];

$logDir = __DIR__ . '/logs';
if (!is_dir($logDir)) {
    @mkdir($logDir, 0755, true);
}
$denyFile = $logDir . '/.htaccess';
if (!file_exists($denyFile)) {
    @file_put_contents($denyFile, "Require all denied\nDeny from all\n", LOCK_EX);
}
$file = $logDir . '/events-' . gmdate('Y-m') . '.jsonl';
$ok = @file_put_contents($file, json_encode($row, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n", FILE_APPEND | LOCK_EX);

http_response_code($ok === false ? 500 : 204);
exit;
