safeLoad(); const JSON_OPTS = JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE; function json($data, int $code=200): void { http_response_code($code); header('Content-Type: application/json; charset=utf-8'); echo json_encode($data, JSON_OPTS); exit; } function db(): PDO { static $pdo; if ($pdo) return $pdo; $path = $_ENV['SQLITE_PATH'] ?? (__DIR__.'/iot.sqlite'); $pdo = new PDO('sqlite:'.$path, null, null, [ PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC, ]); $pdo->exec(" CREATE TABLE IF NOT EXISTS device (id TEXT PRIMARY KEY, token TEXT NOT NULL, created_at TEXT NOT NULL); CREATE TABLE IF NOT EXISTS reading (id INTEGER PRIMARY KEY AUTOINCREMENT, device_id TEXT NOT NULL, ts INTEGER NOT NULL, data TEXT NOT NULL); CREATE INDEX IF NOT EXISTS idx_reading_dev_ts ON reading(device_id, ts); "); return $pdo; } function require_token(PDO $pdo): string { $hdr=$_SERVER['HTTP_AUTHORIZATION']??''; $api=$_SERVER['HTTP_X_API_KEY']??''; $t=''; if (preg_match('/Bearer\s+(.+)/i',$hdr,$m)) $t=trim($m[1]); elseif ($api) $t=$api; if ($t==='') json(['error'=>'missing token'],401); $st=$pdo->prepare("SELECT id FROM device WHERE token=:t LIMIT 1"); $st->execute([':t'=>$t]); $r=$st->fetch(); if(!$r) json(['error'=>'invalid token'],401); return $r['id']; }