SIMON Master Console Rebuild
True command center for SIMON + WEB360
This rebuild gives you a cleaner production spine: interactive tree, live viewer, guarded editor, dynamic graphics, architecture map, and note storage. It is designed to sit beside your existing
console.php
and become the stronger replacement path.
Dashboard
Tree
Viewer
System Map
File Registry
Notes
Files
15,334
Folders
408
Scanned Size
3.84 GB
PHP Files
886
Editable Text Files
12,595
File viewer
guarded to /htdocs
/connlink/test1/ui/old/webhook_inbox.php
<?php /* ============================================================ * SIMON · Webhook Inbox * ------------------------------------------------------------ * GET /webhook_inbox.php?stream=NAME&since=ISO -> { items: [...] } * POST /webhook_inbox.php?stream=NAME -> stores payload * * Upload to: /htdocs/connlink/test1/ui/webhook_inbox.php * Reached at: https://www.gaylordsinclair.com/connlink/test1/ui/webhook_inbox.php * * Accepts any JSON body (Perior, Zapier, n8n, Make, IFTTT, curl). * Stores payloads as newline-delimited JSON in /data/webhook_STREAM.ndjson * SIMON polls GET; Perior (and friends) POST. * * Security options (any one is enough — all are optional): * 1. ?key=SECRET — simple shared-secret in the webhook URL. * Easiest to set up in Perior/Zapier. * 2. X-Signature — HMAC-SHA256(body, SECRET) in a header. * Only if the sender can sign payloads. * 3. Leave SIMON_WEBHOOK_SECRET empty → open inbox (default). * * Secrets file (optional): ./secrets.php returning an array * return [ 'SIMON_WEBHOOK_SECRET' => '...' ]; * Falls back to env: SIMON_WEBHOOK_SECRET * ============================================================ */ header('Content-Type: application/json; charset=utf-8'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Signature'); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; } /* ----- config ----- */ $DATA_DIR = __DIR__ . '/data'; $MAX_EVENTS_PER_STREAM = 500; $RETENTION_DAYS = 14; /* ----- load secrets (tries /private/secure/ first, then local, then env) ----- */ $SECRET = ''; $secretPaths = [ dirname($_SERVER['DOCUMENT_ROOT'] ?? '') . '/private/secure/secrets.php', __DIR__ . '/secrets.php', ]; foreach ($secretPaths as $sp) { if ($sp && file_exists($sp)) { $s = @include $sp; if (is_array($s) && !empty($s['SIMON_WEBHOOK_SECRET'])) { $SECRET = $s['SIMON_WEBHOOK_SECRET']; break; } } } if ($SECRET === '') { $SECRET = getenv('SIMON_WEBHOOK_SECRET') ?: ''; } /* ----- prep ----- */ if (!is_dir($DATA_DIR)) { @mkdir($DATA_DIR, 0755, true); } $stream = preg_replace('/[^A-Za-z0-9_-]/', '', $_GET['stream'] ?? 'default'); if ($stream === '') $stream = 'default'; $file = $DATA_DIR . '/webhook_' . $stream . '.ndjson'; /* ============================================================ * POST — receive a webhook * ============================================================ */ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $raw = file_get_contents('php://input'); if ($SECRET !== '') { // Accept EITHER a valid X-Signature HMAC OR a matching ?key=SECRET. $sig = $_SERVER['HTTP_X_SIGNATURE'] ?? ''; $expected = hash_hmac('sha256', $raw, $SECRET); $sigOk = ($sig !== '' && hash_equals($expected, $sig)); $keyOk = (isset($_GET['key']) && hash_equals($SECRET, (string)$_GET['key'])); if (!$sigOk && !$keyOk) { http_response_code(401); echo json_encode(['ok' => false, 'err' => 'unauthorized (need ?key=SECRET or X-Signature header)']); exit; } } $body = json_decode($raw, true); if (!is_array($body)) { if (!empty($_POST)) { $body = $_POST; } else { $body = ['_raw' => $raw]; } } $event = [ 'received_at' => gmdate('c'), 'stream' => $stream, 'ip' => $_SERVER['REMOTE_ADDR'] ?? '', 'ua' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'headers' => array_change_key_case(array_filter($_SERVER, function($k){ return strpos($k,'HTTP_')===0; }, ARRAY_FILTER_USE_KEY)), 'payload' => $body, 'title' => $body['title'] ?? $body['subject'] ?? $body['name'] ?? $body['event'] ?? $body['headline'] ?? null, 'summary' => $body['summary'] ?? $body['description'] ?? $body['body'] ?? $body['message'] ?? $body['text'] ?? null, 'url' => $body['url'] ?? $body['link'] ?? $body['href'] ?? null, ]; if (empty($event['title'])) { $event['title'] = '(Webhook) ' . $event['received_at']; } if (empty($event['summary'])) { $event['summary'] = substr(json_encode($body, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE), 0, 500); } $line = json_encode($event, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE) . "\n"; @file_put_contents($file, $line, FILE_APPEND | LOCK_EX); trim_file($file, $MAX_EVENTS_PER_STREAM, $RETENTION_DAYS); echo json_encode(['ok' => true, 'stream' => $stream, 'stored' => 1]); exit; } /* ============================================================ * GET — list recent events * ============================================================ */ if (!file_exists($file)) { echo json_encode(['items' => [], 'stream' => $stream]); exit; } $since = $_GET['since'] ?? ''; $limit = max(1, min(500, intval($_GET['limit'] ?? 50))); $lines = array_reverse(file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: []); $out = []; foreach ($lines as $ln) { $e = json_decode($ln, true); if (!is_array($e)) continue; if ($since !== '' && isset($e['received_at']) && $e['received_at'] <= $since) continue; $out[] = [ 'title' => $e['title'] ?? '(Webhook)', 'summary' => $e['summary'] ?? '', 'url' => $e['url'] ?? '#', 'at' => $e['received_at'] ?? gmdate('c'), 'timestamp' => $e['received_at'] ?? gmdate('c'), 'stream' => $e['stream'] ?? $stream, 'payload' => $e['payload'] ?? null, ]; if (count($out) >= $limit) break; } echo json_encode(['items' => $out, 'stream' => $stream, 'count' => count($out)]); /* ============================================================ * helpers * ============================================================ */ function trim_file($file, $maxLines, $retentionDays) { if (!file_exists($file)) return; $cutoff = gmdate('c', time() - $retentionDays * 86400); $lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: []; $keep = []; foreach ($lines as $ln) { $e = json_decode($ln, true); if (!is_array($e)) continue; if (isset($e['received_at']) && $e['received_at'] < $cutoff) continue; $keep[] = $ln; } if (count($keep) > $maxLines) $keep = array_slice($keep, -$maxLines); @file_put_contents($file, implode("\n", $keep) . "\n", LOCK_EX); }
Save file
Quick jump
open a path
Open