|
|
@@ -0,0 +1,198 @@
|
|
|
+<?php
|
|
|
+declare(strict_types=1);
|
|
|
+
|
|
|
+$baseUrl = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']);
|
|
|
+$dataPath = __DIR__ . '/data/webhooks.json';
|
|
|
+
|
|
|
+// Validate key parameter
|
|
|
+if (!isset($_GET['key']) || empty($_GET['key'])) {
|
|
|
+ http_response_code(400);
|
|
|
+ die('<h1>Error: Missing key parameter</h1>');
|
|
|
+}
|
|
|
+
|
|
|
+$key = $_GET['key'];
|
|
|
+
|
|
|
+// Load webhooks
|
|
|
+$raw = file_get_contents($dataPath);
|
|
|
+$data = json_decode($raw, true);
|
|
|
+
|
|
|
+// Find the webhook
|
|
|
+$webhook = null;
|
|
|
+foreach ($data['webhooks'] as $w) {
|
|
|
+ if ($w['key'] === $key) {
|
|
|
+ $webhook = $w;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+if ($webhook === null) {
|
|
|
+ http_response_code(404);
|
|
|
+ die('<h1>Error: Webhook not found</h1>');
|
|
|
+}
|
|
|
+
|
|
|
+// Reverse requests to show newest first
|
|
|
+$requests = array_reverse($webhook['requests']);
|
|
|
+
|
|
|
+// Helper function to format JSON
|
|
|
+function formatJson($string) {
|
|
|
+ $decoded = json_decode($string, true);
|
|
|
+ if (json_last_error() === JSON_ERROR_NONE) {
|
|
|
+ return json_encode($decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
|
|
+ }
|
|
|
+ return $string;
|
|
|
+}
|
|
|
+
|
|
|
+// Helper function to format headers
|
|
|
+function formatHeaders($headers) {
|
|
|
+ $output = '';
|
|
|
+ foreach ($headers as $name => $value) {
|
|
|
+ $output .= htmlspecialchars($name) . ': ' . htmlspecialchars($value) . "\n";
|
|
|
+ }
|
|
|
+ return rtrim($output);
|
|
|
+}
|
|
|
+?>
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="en">
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
+ <title>Webhook: <?= htmlspecialchars($webhook['key']) ?></title>
|
|
|
+ <style>
|
|
|
+ body {
|
|
|
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
+ max-width: 1400px;
|
|
|
+ margin: 40px auto;
|
|
|
+ padding: 0 20px;
|
|
|
+ background: #f5f5f5;
|
|
|
+ }
|
|
|
+ h1 { color: #333; }
|
|
|
+ .info { background: #e3f2fd; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
|
|
|
+ .url-box {
|
|
|
+ background: #fff;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 3px;
|
|
|
+ font-family: monospace;
|
|
|
+ font-size: 13px;
|
|
|
+ word-break: break-all;
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ }
|
|
|
+ .btn {
|
|
|
+ display: inline-block;
|
|
|
+ padding: 8px 16px;
|
|
|
+ background: #2196F3;
|
|
|
+ color: white;
|
|
|
+ text-decoration: none;
|
|
|
+ border-radius: 5px;
|
|
|
+ border: none;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ .btn:hover { background: #1976D2; }
|
|
|
+ .btn-secondary { background: #757575; }
|
|
|
+ .btn-secondary:hover { background: #616161; }
|
|
|
+ .request {
|
|
|
+ background: white;
|
|
|
+ border-radius: 5px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ .request-header {
|
|
|
+ background: #2196F3;
|
|
|
+ color: white;
|
|
|
+ padding: 12px 15px;
|
|
|
+ font-weight: bold;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ .request-method {
|
|
|
+ background: rgba(255,255,255,0.2);
|
|
|
+ padding: 3px 8px;
|
|
|
+ border-radius: 3px;
|
|
|
+ font-size: 12px;
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+ .request-body {
|
|
|
+ padding: 15px;
|
|
|
+ }
|
|
|
+ .section {
|
|
|
+ margin-bottom: 15px;
|
|
|
+ }
|
|
|
+ .section-title {
|
|
|
+ font-weight: bold;
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ font-size: 13px;
|
|
|
+ text-transform: uppercase;
|
|
|
+ }
|
|
|
+ .code-box {
|
|
|
+ background: #f5f5f5;
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ border-radius: 3px;
|
|
|
+ padding: 10px;
|
|
|
+ font-family: 'Courier New', monospace;
|
|
|
+ font-size: 12px;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ word-break: break-all;
|
|
|
+ max-height: 400px;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+ .empty { text-align: center; color: #999; padding: 40px; }
|
|
|
+ .back-link { margin-bottom: 20px; display: inline-block; }
|
|
|
+ </style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+ <a href="index.php" class="back-link btn btn-secondary">← Back to Webhooks</a>
|
|
|
+
|
|
|
+ <h1>🔗 Webhook Details</h1>
|
|
|
+
|
|
|
+ <div class="info">
|
|
|
+ <div><strong>Key:</strong> <code><?= htmlspecialchars($webhook['key']) ?></code></div>
|
|
|
+ <div style="margin-top: 10px;"><strong>Created:</strong> <?= htmlspecialchars(date('Y-m-d H:i:s', strtotime($webhook['created']))) ?></div>
|
|
|
+ <div style="margin-top: 10px;"><strong>Webhook URL:</strong></div>
|
|
|
+ <div class="url-box" style="margin-top: 5px;">
|
|
|
+ <?= htmlspecialchars($baseUrl . '/webhook.php?key=' . $webhook['key']) ?>
|
|
|
+ </div>
|
|
|
+ <div style="margin-top: 10px;"><strong>Total Requests:</strong> <?= count($webhook['requests']) ?></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <h2>Received Requests</h2>
|
|
|
+
|
|
|
+ <?php if (empty($requests)): ?>
|
|
|
+ <div class="empty">No requests received yet. Send a POST request to the webhook URL above.</div>
|
|
|
+ <?php else: ?>
|
|
|
+ <?php foreach ($requests as $index => $request): ?>
|
|
|
+ <div class="request">
|
|
|
+ <div class="request-header">
|
|
|
+ <span>
|
|
|
+ <span class="request-method"><?= htmlspecialchars($request['method']) ?></span>
|
|
|
+ Request #<?= count($webhook['requests']) - $index ?>
|
|
|
+ </span>
|
|
|
+ <span style="font-size: 12px; font-weight: normal;">
|
|
|
+ <?= htmlspecialchars(date('Y-m-d H:i:s', strtotime($request['timestamp']))) ?>
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="request-body">
|
|
|
+ <div class="section">
|
|
|
+ <div class="section-title">Headers</div>
|
|
|
+ <div class="code-box"><?= formatHeaders($request['headers']) ?></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="section">
|
|
|
+ <div class="section-title">Body</div>
|
|
|
+ <?php
|
|
|
+ $isJson = false;
|
|
|
+ if (isset($request['headers']['Content-Type']) &&
|
|
|
+ strpos($request['headers']['Content-Type'], 'application/json') !== false) {
|
|
|
+ $isJson = true;
|
|
|
+ }
|
|
|
+ ?>
|
|
|
+ <div class="code-box"><?= htmlspecialchars($isJson ? formatJson($request['body']) : $request['body']) ?></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <?php endforeach; ?>
|
|
|
+ <?php endif; ?>
|
|
|
+</body>
|
|
|
+</html>
|