ich habe mir mit der API ein interface für die DNS Verwaltung gebastelt, jedoch habe ich das Problem das die DNS Einträge nicht in Keyhelp überschrieben werden sondern diese werden immer auf Standard werte zurückgesetzt hat jemand eine Idee ich steh echt etwas aufm schlauch =(
PS: über KI hab ichs schon versucht aber auch nicht wirklich hilfreich.
Code: Select all
config.php
<?php
return [
'db' => [
'dsn' => 'mysql:host=xxx;dbname=xxx;charset=utf8mb4',
'user' => 'xxxxx',
'pass' => 'xxxxx',
],
// KeyHelp API
'keyhelp' => [
'base_url' => 'https://xxxxxx/api/v2.13',
'api_key' => 'xxxxxxxxxxxxxxxx',
'endpoints' => [
'domains_list' => '/domains', // GET
'dns_get' => '/dns/{domainId}', // GET
'dns_put' => '/dns/{domainId}', // PUT (vollständiger Satz)
],
'auth_header' => 'X-API-Key',
],
'session_name' => 'dns_panel_sess',
];
Code: Select all
dns.php
<?php
require __DIR__ . '/src/bootstrap.php';
require_login();
$domainId = (int)($_GET['domain_id'] ?? 0);
if (!$domainId) { header('Location: /domains.php'); exit; }
if (function_exists('is_customer') && is_customer()) {
$uid = (int)($_SESSION['user_id'] ?? 0);
$st = $pdo->prepare("SELECT 1 FROM user_domains WHERE user_id=? AND domain_id=?");
$st->execute([$uid, $domainId]);
if (!$st->fetchColumn()) { http_response_code(403); exit("Forbidden"); }
}
$st = $pdo->prepare("SELECT id, domain_name, keyhelp_domain_id FROM domains WHERE id=?");
$st->execute([$domainId]);
$domain = $st->fetch();
if (!$domain) { http_response_code(404); exit("Domain nicht gefunden"); }
if (!$domain['keyhelp_domain_id']) { exit("Domain-ID fehlt bei dieser Domain"); }
$remoteDomainId = (int)$domain['keyhelp_domain_id'];
$error = null; $ok = null;
$dns = null;
function pick(array $arr, array $keys, $default=null) {
foreach ($keys as $k) if (array_key_exists($k, $arr)) return $arr[$k];
return $default;
}
function i($v): int { return (int)preg_replace('/[^0-9]/', '', (string)$v); }
function is_assoc(array $a): bool { return array_keys($a) !== range(0, count($a)-1); }
function get_records_container_key(array $dns): ?string {
foreach (['records','dns_records','entries','zone_records','custom_records'] as $k) {
if (array_key_exists($k, $dns) && is_array($dns[$k])) return $k;
}
return null;
}
function display_value(array $raw): string {
$type = strtoupper((string)pick($raw, ['type'], ''));
$prio = pick($raw, ['priority','prio'], null);
$target = pick($raw, ['exchange','target','destination','value','content','data'], '');
if ($type === 'MX' && $prio !== null && $prio !== '') {
return trim((string)$prio . ' ' . (string)$target);
}
if ($type === 'SRV') {
$p = pick($raw, ['priority','prio'], null);
$w = pick($raw, ['weight'], null);
$port = pick($raw, ['port'], null);
$t = pick($raw, ['target','destination','value','content','data'], '');
$parts = [];
if ($p!==null && $p!=='') $parts[]=(string)$p;
if ($w!==null && $w!=='') $parts[]=(string)$w;
if ($port!==null && $port!=='') $parts[]=(string)$port;
if ((string)$t!=='') $parts[]=(string)$t;
return trim(implode(' ', $parts));
}
return (string)pick($raw, ['value','content','data','target','destination','exchange'], '');
}
function flatten_records($records): array {
$out = [];
if (!is_array($records)) return $out;
if (is_assoc($records)) {
foreach ($records as $group => $list) {
if (!is_array($list)) continue;
foreach ($list as $r) {
if (!is_array($r)) continue;
$out[] = [
'group' => (string)$group,
'id' => $r['id'] ?? null,
'host' => (string)pick($r, ['host','hostname','name'], ''),
'ttl' => (string)pick($r, ['ttl'], ''),
'type' => strtoupper((string)pick($r, ['type'], 'A')),
'value' => display_value($r),
'_raw' => $r,
];
}
}
} else {
foreach ($records as $r) {
if (!is_array($r)) continue;
$out[] = [
'group' => 'other',
'id' => $r['id'] ?? null,
'host' => (string)pick($r, ['host','hostname','name'], ''),
'ttl' => (string)pick($r, ['ttl'], ''),
'type' => strtoupper((string)pick($r, ['type'], 'A')),
'value' => display_value($r),
'_raw' => $r,
];
}
}
return $out;
}
function apply_record_edit(array $raw, string $host, string $type, string $value, string $ttl): array {
if (array_key_exists('hostname', $raw)) $raw['hostname'] = $host;
elseif (array_key_exists('host', $raw)) $raw['host'] = $host;
elseif (array_key_exists('name', $raw)) $raw['name'] = $host;
else $raw['host'] = $host;
$raw['type'] = $type;
if ($ttl !== '') $raw['ttl'] = i($ttl);
foreach (['value','content','data','target','destination','exchange','priority','weight','port','prio'] as $k) {
if (in_array($k, ['priority','weight','port','prio','exchange','target','destination','value','content','data'], true)) {
}
}
if ($type === 'MX') {
$m = [];
if (preg_match('/^\s*(\d+)\s+(.+)\s*$/', $value, $m)) {
$raw['priority'] = (int)$m[1];
$t = trim($m[2]);
if (array_key_exists('exchange', $raw)) $raw['exchange'] = $t;
elseif (array_key_exists('target', $raw)) $raw['target'] = $t;
elseif (array_key_exists('destination', $raw)) $raw['destination'] = $t;
else $raw['value'] = $t;
} else {
if (array_key_exists('value', $raw)) $raw['value'] = $value;
elseif (array_key_exists('content', $raw)) $raw['content'] = $value;
else $raw['value'] = $value;
}
return $raw;
}
if ($type === 'SRV') {
$parts = preg_split('/\s+/', trim($value));
if (count($parts) >= 4 && ctype_digit($parts[0]) && ctype_digit($parts[1]) && ctype_digit($parts[2])) {
$raw['priority'] = (int)$parts[0];
$raw['weight'] = (int)$parts[1];
$raw['port'] = (int)$parts[2];
$t = implode(' ', array_slice($parts, 3));
if (array_key_exists('target', $raw)) $raw['target'] = $t;
elseif (array_key_exists('destination', $raw)) $raw['destination'] = $t;
else $raw['value'] = $t;
} else {
if (array_key_exists('value', $raw)) $raw['value'] = $value;
elseif (array_key_exists('content', $raw)) $raw['content'] = $value;
else $raw['value'] = $value;
}
return $raw;
}
if (array_key_exists('content', $raw)) $raw['content'] = $value;
elseif (array_key_exists('data', $raw)) $raw['data'] = $value;
elseif (array_key_exists('target', $raw) && in_array($type, ['CNAME','NS','PTR','TLSA','NAPTR','CAA'], true)) $raw['target'] = $value;
elseif (array_key_exists('destination', $raw)) $raw['destination'] = $value;
elseif (array_key_exists('value', $raw)) $raw['value'] = $value;
else $raw['value'] = $value;
return $raw;
}
try {
$dns = $keyhelp->getDns($remoteDomainId);
} catch (Throwable $e) {
$error = $e->getMessage();
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$current = $keyhelp->getDns($remoteDomainId);
if (!is_array($current)) throw new RuntimeException("Unerwartetes DNS-Format");
$containerKey = get_records_container_key($current);
if (!$containerKey) throw new RuntimeException("DNS Records nicht gefunden");
$recordsContainer = $current[$containerKey];
$grouped = is_array($recordsContainer) && is_assoc($recordsContainer);
$zoneTtl = trim($_POST['zone_ttl'] ?? '');
if ($zoneTtl !== '') {
if (array_key_exists('ttl', $current)) $current['ttl'] = i($zoneTtl);
elseif (array_key_exists('default_ttl', $current)) $current['default_ttl'] = i($zoneTtl);
else $current['ttl'] = i($zoneTtl);
}
$soa = is_array(pick($current, ['soa'], null)) ? $current['soa'] : [];
$soaPrimary = trim($_POST['soa_primary_ns'] ?? '');
$soaRname = trim($_POST['soa_rname'] ?? '');
$soaRefresh = trim($_POST['soa_refresh'] ?? '');
$soaRetry = trim($_POST['soa_retry'] ?? '');
$soaExpire = trim($_POST['soa_expire'] ?? '');
$soaMinTtl = trim($_POST['soa_minimum'] ?? '');
if ($soaPrimary !== '') $soa['primary_ns'] = $soaPrimary;
if ($soaRname !== '') $soa['rname'] = $soaRname;
if ($soaRefresh !== '') $soa['refresh'] = i($soaRefresh);
if ($soaRetry !== '') $soa['retry'] = i($soaRetry);
if ($soaExpire !== '') $soa['expire'] = i($soaExpire);
if ($soaMinTtl !== '') $soa['minimum'] = i($soaMinTtl);
if (!empty($soa)) $current['soa'] = $soa;
$ids = $_POST['rec_id'] ?? [];
$groups = $_POST['rec_group'] ?? [];
$hosts = $_POST['rec_host'] ?? [];
$ttls = $_POST['rec_ttl'] ?? [];
$types = $_POST['rec_type'] ?? [];
$values = $_POST['rec_value'] ?? [];
$raws = $_POST['rec_raw'] ?? [];
if (!is_array($hosts) || !is_array($types) || !is_array($values)) {
throw new RuntimeException("Ungültige Eingaben");
}
if ($grouped) $newContainer = []; else $newContainer = [];
$n = max(count($hosts), count($types), count($values));
for ($k=0; $k<$n; $k++) {
$host = strtolower(trim((string)($hosts[$k] ?? '')));
$type = strtoupper(trim((string)($types[$k] ?? 'A')));
$val = trim((string)($values[$k] ?? ''));
$ttl = trim((string)($ttls[$k] ?? ''));
$grp = strtolower(trim((string)($groups[$k] ?? 'other')));
if ($grp === '') $grp = 'other';
if ($host === '' && $val === '' && $type === '') continue;
if ($type === '') $type = 'A';
$base = [];
if (!empty($raws[$k])) {
$tmp = json_decode((string)$raws[$k], true);
if (is_array($tmp)) $base = $tmp;
}
$id = $ids[$k] ?? null;
if ($id !== null && $id !== '') $base['id'] = $id;
$base = apply_record_edit($base, $host, $type, $val, $ttl);
if ($grouped) {
if (!isset($newContainer[$grp]) || !is_array($newContainer[$grp])) $newContainer[$grp] = [];
$newContainer[$grp][] = $base;
} else {
$newContainer[] = $base;
}
}
$current[$containerKey] = $newContainer;
$keyhelp->putDns($remoteDomainId, $current);
$after = $keyhelp->getDns($remoteDomainId);
$beforeHash = hash('sha256', json_encode($current, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
$afterHash = hash('sha256', json_encode($after, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
if ($beforeHash !== $afterHash) {
$ok = "Gespeichert";
} else {
$ok = "Gespeichert";
}
if (function_exists('is_staff') && is_staff()) {
audit($pdo, 'DNS_UPDATE', 'domain_id=' . $domainId);
}
$dns = $after;
} catch (Throwable $e) {
$error = $e->getMessage();
}
}
$zoneHost = (string)pick($dns ?? [], ['host','domain','zone','name'], $domain['domain_name']);
$zoneTtlV = pick($dns ?? [], ['ttl','default_ttl'], '');
$soa = is_array(pick($dns ?? [], ['soa'], null)) ? $dns['soa'] : [];
$containerKey = is_array($dns) ? get_records_container_key($dns) : null;
$recordsContainer = ($containerKey && is_array($dns[$containerKey] ?? null)) ? $dns[$containerKey] : [];
$records = flatten_records($recordsContainer);
$types = ['A','AAAA','CNAME','MX','NS','TXT','SRV','CAA','PTR','NAPTR','TLSA'];
render_header("DNS: " . $domain['domain_name']);
?>
Code: Select all
keyhelp.php
<?php
final class KeyHelpClient {
private string $baseUrl;
private string $apiKey;
private string $authHeader;
private array $ep;
public function __construct(array $cfg) {
$this->baseUrl = rtrim($cfg['base_url'], '/');
$this->apiKey = $cfg['api_key'];
$this->authHeader = $cfg['auth_header'] ?? 'X-API-Key';
$this->ep = $cfg['endpoints'];
}
private function request(string $method, string $path, ?array $json = null): array {
$url = $this->baseUrl . $path;
$ch = curl_init($url);
$headers = [
'Accept: application/json',
'Content-Type: application/json',
$this->authHeader . ': ' . $this->apiKey,
];
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_ENCODING => '',
CURLOPT_USERAGENT => 'dns-panel/1.0',
]);
if ($json !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($json, JSON_UNESCAPED_UNICODE));
}
$body = curl_exec($ch);
$code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err = curl_error($ch);
curl_close($ch);
if ($body === false) {
throw new RuntimeException("KeyHelp API cURL error for $url: $err");
}
$decoded = json_decode($body, true);
$isJson = is_array($decoded);
if ($code < 200 || $code >= 300) {
$msg = $isJson ? json_encode($decoded, JSON_UNESCAPED_UNICODE) : $body;
throw new RuntimeException("KeyHelp API HTTP $code for $url: $msg");
}
return $isJson ? $decoded : [];
}
private function withId(string $tpl, int $domainId): string {
return str_replace('{domainId}', (string)$domainId, $tpl);
}
public function listDomains(array $query = []): array {
$path = $this->ep['domains_list'];
if ($query) $path .= '?' . http_build_query($query);
return $this->request('GET', $path);
}
public function getDns(int $domainId): array {
return $this->request('GET', $this->withId($this->ep['dns_get'], $domainId));
}
public function putDns(int $domainId, array $payload): array {
return $this->request('PUT', $this->withId($this->ep['dns_put'], $domainId), $payload);
}
}