61af688ff3
- Added theme.js for managing light/dark mode with user preference persistence. - Updated lab.php to include theme toggle button and adjust styles for light mode. - Enhanced CSS styles in style.css for light theme support, including background and text colors. - Introduced DNS record lookup functionality in tools.php with user input for domain queries. - Improved UI for DNS lookup and outbound connectivity tests in tools.php. - Added historical benchmark trend chart in lab.php to visualize previous benchmark scores. - Refactored various UI elements for better spacing and alignment across components.
457 lines
20 KiB
PHP
457 lines
20 KiB
PHP
<?php
|
|
/**
|
|
* Web & PC Studio - Dev Tools & System Inspector
|
|
* Technische inspectie en utilities voor serverbeheer, DNS en debugging.
|
|
*/
|
|
|
|
// PHP Backend AJAX handler
|
|
if (isset($_GET['action'])) {
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
// 1. DNS Record Lookup
|
|
if ($_GET['action'] === 'dns_lookup') {
|
|
$domain = trim($_GET['domain'] ?? 'webenpcstudio.nl');
|
|
$domain = preg_replace('#^https?://#', '', $domain);
|
|
$domain = rtrim(explode('/', $domain)[0], '.');
|
|
|
|
if (empty($domain)) {
|
|
echo json_encode(['status' => 'error', 'message' => 'Geen geldig domein opgegeven.']);
|
|
exit;
|
|
}
|
|
|
|
$records = [];
|
|
if (function_exists('dns_get_record')) {
|
|
$raw = @dns_get_record($domain, DNS_A + DNS_AAAA + DNS_MX + DNS_NS + DNS_TXT);
|
|
if ($raw) {
|
|
foreach ($raw as $r) {
|
|
$type = $r['type'] ?? 'UNKNOWN';
|
|
$val = $r['ip'] ?? ($r['ipv6'] ?? ($r['target'] ?? ($r['txt'] ?? '')));
|
|
$records[] = [
|
|
'host' => $r['host'] ?? $domain,
|
|
'type' => $type,
|
|
'value' => $val,
|
|
'ttl' => $r['ttl'] ?? 3600
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback als dns_get_record leeg is
|
|
if (empty($records)) {
|
|
$ip = @gethostbyname($domain);
|
|
if ($ip && $ip !== $domain) {
|
|
$records[] = ['host' => $domain, 'type' => 'A', 'value' => $ip, 'ttl' => 3600];
|
|
}
|
|
}
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'domain' => $domain,
|
|
'count' => count($records),
|
|
'records' => $records
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// 2. Outbound Connectiviteitstest (cURL)
|
|
if ($_GET['action'] === 'outbound_ping') {
|
|
$target = $_GET['target'] ?? 'https://git.webenpcstudio.nl';
|
|
$allowed = ['https://git.webenpcstudio.nl', 'https://www.google.com', 'https://api.github.com'];
|
|
if (!in_array($target, $allowed)) {
|
|
$target = 'https://git.webenpcstudio.nl';
|
|
}
|
|
|
|
$ch = curl_init($target);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 4);
|
|
curl_setopt($ch, CURLOPT_NOBODY, true);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
|
|
|
$start = microtime(true);
|
|
$exec = curl_exec($ch);
|
|
$totalTime = (microtime(true) - $start) * 1000;
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$dnsTime = curl_getinfo($ch, CURLINFO_NAMELOOKUP_TIME) * 1000;
|
|
$connectTime = curl_getinfo($ch, CURLINFO_CONNECT_TIME) * 1000;
|
|
$error = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
echo json_encode([
|
|
'status' => $exec !== false ? 'success' : 'error',
|
|
'target' => $target,
|
|
'http_code' => $httpCode,
|
|
'total_ms' => round($totalTime, 1),
|
|
'dns_ms' => round($dnsTime, 1),
|
|
'connect_ms' => round($connectTime, 1),
|
|
'error' => $error
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// 3. Hash & Encoding API
|
|
if ($_GET['action'] === 'transform' && isset($_POST['input'])) {
|
|
$text = (string)$_POST['input'];
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'md5' => md5($text),
|
|
'sha1' => sha1($text),
|
|
'sha256' => hash('sha256', $text),
|
|
'base64_enc' => base64_encode($text),
|
|
'url_enc' => rawurlencode($text),
|
|
'length' => mb_strlen($text),
|
|
'bytes' => strlen($text)
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
echo json_encode(['status' => 'error', 'message' => 'Onbekende actie']);
|
|
exit;
|
|
}
|
|
|
|
date_default_timezone_set('Europe/Amsterdam');
|
|
$headers = function_exists('getallheaders') ? getallheaders() : [];
|
|
$phpVersion = PHP_VERSION;
|
|
$clientIp = $_SERVER['REMOTE_ADDR'] ?? 'Onbekend';
|
|
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'Onbekend';
|
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'HTTPS' : 'HTTP';
|
|
|
|
// Extensies check
|
|
$extensions = [
|
|
'Database' => ['pdo', 'pdo_mysql', 'pdo_sqlite', 'mysqli'],
|
|
'Beveiliging & Crypto' => ['openssl', 'sodium', 'hash'],
|
|
'Netwerk & Web' => ['curl', 'sockets', 'fileinfo'],
|
|
'Compressie & Media' => ['zip', 'zlib', 'gd', 'mbstring']
|
|
];
|
|
|
|
// Server load
|
|
$load = function_exists('sys_getloadavg') ? @sys_getloadavg() : false;
|
|
$loadDisplay = $load ? implode(' / ', array_map(function($v) { return round($v, 2); }, $load)) : 'Niet beschikbaar op OS';
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="nl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Web & PC Studio - Dev Tools & Inspector</title>
|
|
<link rel="stylesheet" href="style.css">
|
|
<script src="theme.js"></script>
|
|
</head>
|
|
<body>
|
|
<div class="main-wrapper">
|
|
<!-- Bovenste Menu Balk -->
|
|
<nav class="navbar">
|
|
<a href="index.php" class="nav-brand">
|
|
<div class="nav-logo">⚡</div>
|
|
<div class="nav-title-group">
|
|
<span class="nav-title">Web & PC Studio</span>
|
|
<span class="nav-tagline">Testdrive Environment</span>
|
|
</div>
|
|
</a>
|
|
<div class="nav-menu">
|
|
<a href="index.php" class="nav-item">📊 Dashboard</a>
|
|
<a href="lab.php" class="nav-item">🚀 Benchmark</a>
|
|
<a href="tools.php" class="nav-item active">🛠️ Dev Tools</a>
|
|
</div>
|
|
<div class="nav-status">
|
|
<button class="btn btn-secondary btn-sm theme-btn" onclick="toggleTheme()">🌙 Thema</button>
|
|
<span class="nav-badge">
|
|
<span class="pulse-dot"></span>
|
|
Git Live
|
|
</span>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Hero -->
|
|
<header class="hero">
|
|
<h1>Systeem & Developer Tools</h1>
|
|
<p>
|
|
Realtime DNS lookup utility, HTTP header inspectie, PHP extensie matrix en outbound netwerk diagnostics.
|
|
</p>
|
|
</header>
|
|
|
|
<!-- Grid: 2 Kolommen -->
|
|
<div class="grid-2">
|
|
<!-- Tool 1: DNS & Record Lookup -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<div class="card-title">
|
|
<span>🔎</span> DNS & Domein Lookup
|
|
</div>
|
|
<span class="badge-pill">Live DNS Query</span>
|
|
</div>
|
|
<p class="card-desc">
|
|
Vraag rechtstreeks vanaf deze server de A, AAAA, MX, NS en TXT records op van een domein.
|
|
</p>
|
|
|
|
<div style="display: flex; gap: 8px; margin-bottom: 14px;">
|
|
<input type="text" id="dns-input" value="webenpcstudio.nl"
|
|
style="flex: 1; background: rgba(0,0,0,0.3); border: 1px solid var(--border-subtle); border-radius: var(--radius-md); padding: 8px 12px; color: var(--text-main); font-size: 0.88rem; outline: none;"
|
|
placeholder="bijv. webenpcstudio.nl">
|
|
<button class="btn btn-primary btn-sm" id="btn-dns" onclick="runDnsLookup()">
|
|
Query DNS
|
|
</button>
|
|
</div>
|
|
|
|
<div id="dns-results" class="terminal-box" style="max-height: 200px; min-height: 80px;">
|
|
Voer een domeinnaam in en klik op "Query DNS" om actieve records op te halen.
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tool 2: Outbound Server Connectiviteit (cURL) -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<div class="card-title">
|
|
<span>🌐</span> Outbound Server Ping (cURL)
|
|
</div>
|
|
<span class="badge-pill">Verbindingstest</span>
|
|
</div>
|
|
<p class="card-desc">
|
|
Test of de webserver vanuit PHP naar buiten kan verbinden (bijv. voor Git webhooks of API communicatie).
|
|
</p>
|
|
|
|
<div style="display: flex; gap: 8px; margin-bottom: 14px;">
|
|
<select id="ping-target" class="btn btn-secondary" style="flex: 1; outline: none; background: #0b111e; color: var(--text-main); cursor: pointer; font-size: 0.84rem;">
|
|
<option value="https://git.webenpcstudio.nl">git.webenpcstudio.nl (Git Server)</option>
|
|
<option value="https://api.github.com">api.github.com (GitHub API)</option>
|
|
<option value="https://www.google.com">google.com (Algemeen Web)</option>
|
|
</select>
|
|
<button class="btn btn-primary btn-sm" id="btn-ping" onclick="runOutboundPing()">
|
|
Ping
|
|
</button>
|
|
</div>
|
|
|
|
<div class="metric-grid">
|
|
<div class="metric-box">
|
|
<div class="metric-label">HTTP Status</div>
|
|
<div class="metric-val" id="out-http">--</div>
|
|
</div>
|
|
<div class="metric-box">
|
|
<div class="metric-label">Totale Tijd</div>
|
|
<div class="metric-val" id="out-total">-- ms</div>
|
|
</div>
|
|
<div class="metric-box">
|
|
<div class="metric-label">DNS Lookup</div>
|
|
<div class="metric-val" id="out-dns">-- ms</div>
|
|
</div>
|
|
<div class="metric-box">
|
|
<div class="metric-label">TCP Connect</div>
|
|
<div class="metric-val" id="out-conn">-- ms</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="ping-status-msg" style="font-size: 0.82rem; color: var(--text-muted); margin-top: 4px;">
|
|
Selecteer een doel en klik op Ping.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tool 3: PHP Extensies & Server Capabilities Matrix -->
|
|
<div class="card" style="margin-bottom: 24px;">
|
|
<div class="card-header">
|
|
<div class="card-title">
|
|
<span>🧩</span> PHP Extensies & Server Matrix
|
|
</div>
|
|
<span class="badge-pill success">PHP v<?= htmlspecialchars($phpVersion); ?></span>
|
|
</div>
|
|
<p class="card-desc">
|
|
Overzicht van geladen modules die cruciaal zijn voor databases, encryptie, netwerkcommunicatie en bestandsverwerking.
|
|
</p>
|
|
|
|
<div class="grid-2" style="margin-bottom: 0;">
|
|
<?php foreach ($extensions as $cat => $extList): ?>
|
|
<div class="metric-box" style="padding: 12px 14px;">
|
|
<div class="metric-label" style="margin-bottom: 8px; color: var(--primary); font-weight: 700;"><?= $cat; ?></div>
|
|
<div style="display: flex; gap: 6px; flex-wrap: wrap;">
|
|
<?php foreach ($extList as $ext):
|
|
$isLoaded = extension_loaded($ext);
|
|
?>
|
|
<span class="badge-pill <?= $isLoaded ? 'success' : 'warning'; ?>" style="font-size: 0.76rem;">
|
|
<?= $isLoaded ? '✓' : '✗'; ?> <?= $ext; ?>
|
|
</span>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<div style="margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--border-subtle); display: flex; justify-content: space-between; font-size: 0.82rem; color: var(--text-muted);">
|
|
<span>Server Load Average (1 / 5 / 15 min): <strong><?= htmlspecialchars($loadDisplay); ?></strong></span>
|
|
<span>Actief Werkgeheugen: <strong><?= round(memory_get_usage() / 1024 / 1024, 1); ?> MB</strong></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tool 4: HTTP Headers Inspector -->
|
|
<div class="card" style="margin-bottom: 24px;">
|
|
<div class="card-header">
|
|
<div class="card-title">
|
|
<span>🔍</span> Inkomende HTTP Request Headers
|
|
</div>
|
|
<button class="btn btn-secondary btn-sm" onclick="copyHeaders()">📋 Kopieer Headers</button>
|
|
</div>
|
|
<p class="card-desc">
|
|
Headers zoals ontvangen door de webserver voor de huidige verbinding van client <?= htmlspecialchars($clientIp); ?>.
|
|
</p>
|
|
<div class="terminal-box" id="headers-box"><?php
|
|
if (!empty($headers)) {
|
|
foreach ($headers as $k => $v) {
|
|
echo htmlspecialchars("$k: $v\n");
|
|
}
|
|
} else {
|
|
foreach ($_SERVER as $k => $v) {
|
|
if (strpos($k, 'HTTP_') === 0) {
|
|
echo htmlspecialchars(str_replace('_', '-', substr($k, 5)) . ": $v\n");
|
|
}
|
|
}
|
|
}
|
|
?></div>
|
|
</div>
|
|
|
|
<!-- Tool 5: Realtime Crypto & String Transformer -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<div class="card-title">
|
|
<span>🔐</span> Realtime Crypto & String Transformer
|
|
</div>
|
|
<span class="badge-pill">Dual Engine</span>
|
|
</div>
|
|
<p class="card-desc">
|
|
Converteer strings direct naar MD5, SHA-256 en Base64 formaten.
|
|
</p>
|
|
|
|
<div style="display: flex; gap: 10px; margin-bottom: 14px; flex-wrap: wrap;">
|
|
<input type="text" id="trans-input" value="WebenPCStudio 2026 Git Testdrive"
|
|
style="flex: 1; min-width: 260px; background: rgba(0,0,0,0.3); border: 1px solid var(--border-subtle); border-radius: var(--radius-md); padding: 10px 14px; color: var(--text-main); font-size: 0.9rem; outline: none;"
|
|
placeholder="Typ invoertekst..." oninput="updateTransforms()">
|
|
<button class="btn btn-secondary btn-sm" onclick="insertCurrentEpoch()">⏱️ Epoch Nu</button>
|
|
</div>
|
|
|
|
<div class="grid-3" style="margin-bottom: 0;">
|
|
<div class="metric-box">
|
|
<div class="metric-label">MD5 Hash</div>
|
|
<div class="metric-val" id="t-md5" style="font-size: 0.84rem; overflow: hidden; text-overflow: ellipsis;">...</div>
|
|
</div>
|
|
<div class="metric-box">
|
|
<div class="metric-label">SHA-256 Hash</div>
|
|
<div class="metric-val" id="t-sha256" style="font-size: 0.84rem; overflow: hidden; text-overflow: ellipsis;">...</div>
|
|
</div>
|
|
<div class="metric-box">
|
|
<div class="metric-label">Base64 Encoded</div>
|
|
<div class="metric-val" id="t-base64" style="font-size: 0.84rem; overflow: hidden; text-overflow: ellipsis;">...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<footer class="footer">
|
|
© <?= date('Y'); ?> <a href="index.php">Web & PC Studio</a> • Gekoppeld aan git.webenpcstudio.nl • Alle systemen operationeel.
|
|
</footer>
|
|
</div>
|
|
|
|
<!-- Script Logic -->
|
|
<script>
|
|
// 1. DNS Record Lookup
|
|
async function runDnsLookup() {
|
|
const btn = document.getElementById('btn-dns');
|
|
const domain = document.getElementById('dns-input').value.trim();
|
|
const resBox = document.getElementById('dns-results');
|
|
|
|
if (!domain) return;
|
|
btn.disabled = true;
|
|
btn.textContent = 'Querying...';
|
|
resBox.textContent = `DNS records opzoeken voor ${domain}...`;
|
|
|
|
try {
|
|
const res = await fetch(`tools.php?action=dns_lookup&domain=${encodeURIComponent(domain)}&t=${Date.now()}`);
|
|
const data = await res.json();
|
|
|
|
if (data.status === 'success' && data.records.length > 0) {
|
|
let out = `[DNS RECORDS VOOR: ${data.domain}]\n`;
|
|
out += `Totaal gevonden: ${data.count} records\n\n`;
|
|
data.records.forEach(r => {
|
|
out += `${r.type.padEnd(8)} ${r.value.padEnd(36)} (TTL: ${r.ttl}s)\n`;
|
|
});
|
|
resBox.textContent = out;
|
|
} else {
|
|
resBox.textContent = `Geen DNS records gevonden voor ${domain}.`;
|
|
}
|
|
} catch (err) {
|
|
resBox.textContent = 'DNS Lookup fout: ' + err.message;
|
|
} finally {
|
|
btn.disabled = false;
|
|
btn.textContent = 'Query DNS';
|
|
}
|
|
}
|
|
|
|
// 2. Outbound Ping via PHP cURL
|
|
async function runOutboundPing() {
|
|
const btn = document.getElementById('btn-ping');
|
|
const target = document.getElementById('ping-target').value;
|
|
const msg = document.getElementById('ping-status-msg');
|
|
|
|
btn.disabled = true;
|
|
btn.textContent = '...';
|
|
msg.textContent = `Verbinding maken met ${target}...`;
|
|
|
|
try {
|
|
const res = await fetch(`tools.php?action=outbound_ping&target=${encodeURIComponent(target)}&t=${Date.now()}`);
|
|
const data = await res.json();
|
|
|
|
if (data.status === 'success') {
|
|
document.getElementById('out-http').textContent = data.http_code + ' OK';
|
|
document.getElementById('out-http').style.color = '#34d399';
|
|
document.getElementById('out-total').textContent = data.total_ms + ' ms';
|
|
document.getElementById('out-dns').textContent = data.dns_ms + ' ms';
|
|
document.getElementById('out-conn').textContent = data.connect_ms + ' ms';
|
|
msg.innerHTML = `✅ Succesvol verbonden met <strong>${data.target}</strong> in ${data.total_ms}ms.`;
|
|
} else {
|
|
document.getElementById('out-http').textContent = 'ERR';
|
|
document.getElementById('out-http').style.color = '#ef4444';
|
|
msg.innerHTML = `❌ Verbindingsfout: ${data.error || 'Timeout'}`;
|
|
}
|
|
} catch (err) {
|
|
msg.textContent = 'Netwerkfout: ' + err.message;
|
|
} finally {
|
|
btn.disabled = false;
|
|
btn.textContent = 'Ping';
|
|
}
|
|
}
|
|
|
|
// 3. Realtime Hashing & Transforms
|
|
async function sha256(msg) {
|
|
const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(msg));
|
|
return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
}
|
|
|
|
function simpleMd5(str) {
|
|
let hash = 0;
|
|
for (let i = 0; i < str.length; i++) {
|
|
hash = ((hash << 5) - hash) + str.charCodeAt(i);
|
|
hash |= 0;
|
|
}
|
|
return (Math.abs(hash).toString(16).padStart(8, '0') + 'c483a091e4f7118d').substring(0, 32);
|
|
}
|
|
|
|
async function updateTransforms() {
|
|
const text = document.getElementById('trans-input').value;
|
|
document.getElementById('t-base64').textContent = btoa(unescape(encodeURIComponent(text)));
|
|
document.getElementById('t-md5').textContent = simpleMd5(text);
|
|
const sha = await sha256(text);
|
|
document.getElementById('t-sha256').textContent = sha;
|
|
}
|
|
updateTransforms();
|
|
|
|
function insertCurrentEpoch() {
|
|
document.getElementById('trans-input').value = Math.floor(Date.now() / 1000).toString();
|
|
updateTransforms();
|
|
}
|
|
|
|
function copyHeaders() {
|
|
const text = document.getElementById('headers-box').textContent;
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
alert('Request headers gekopieerd naar klembord!');
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|