Tee tarjouspyyntölomake toimivaksi (PHP-backend + sähköposti)
Lisätty api.php:hen quote-action joka validoi, tallentaa data/quotes.json-tiedostoon ja lähettää sähköpostin osoitteeseen support@konesaliturku.fi. Sisältää honeypot- bottitorjunnan ja rate limitingin. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
173
api.php
173
api.php
@@ -119,6 +119,179 @@ switch ($action) {
|
|||||||
echo json_encode(['success' => true]);
|
echo json_encode(['success' => true]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'quote':
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
echo json_encode(['error' => 'Method not allowed']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Honeypot
|
||||||
|
if (!empty($_POST['website'])) {
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rate limit
|
||||||
|
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
|
||||||
|
if (!checkRateLimit($ip)) {
|
||||||
|
http_response_code(429);
|
||||||
|
echo json_encode(['error' => 'Liian monta pyyntöä. Yritä myöhemmin uudelleen.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
$name = trim($_POST['name'] ?? '');
|
||||||
|
$email = trim($_POST['email'] ?? '');
|
||||||
|
|
||||||
|
if (!$name || !$email) {
|
||||||
|
echo json_encode(['error' => 'Nimi ja sähköposti ovat pakollisia.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
echo json_encode(['error' => 'Tarkista sähköpostiosoite.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect form data
|
||||||
|
$company = trim($_POST['company'] ?? '');
|
||||||
|
$phone = trim($_POST['phone'] ?? '');
|
||||||
|
$message = trim($_POST['message'] ?? '');
|
||||||
|
|
||||||
|
// Laitepaikat
|
||||||
|
$units1u = intval($_POST['units_1u'] ?? 0);
|
||||||
|
$units2u = intval($_POST['units_2u'] ?? 0);
|
||||||
|
$units4u = intval($_POST['units_4u'] ?? 0);
|
||||||
|
$unitsRack = intval($_POST['units_rack'] ?? 0);
|
||||||
|
|
||||||
|
// Yhteys
|
||||||
|
$connection = $_POST['connection'] ?? '0';
|
||||||
|
$redundantPort = !empty($_POST['redundant_port']);
|
||||||
|
$bgp = intval($_POST['bgp'] ?? 0);
|
||||||
|
|
||||||
|
// VPN
|
||||||
|
$vpn = $_POST['vpn'] ?? '0';
|
||||||
|
|
||||||
|
// Lisäpalvelut
|
||||||
|
$anycastDns = !empty($_POST['anycast_dns']);
|
||||||
|
$blockStorage = !empty($_POST['block_storage']);
|
||||||
|
$s3Storage = !empty($_POST['s3_storage']);
|
||||||
|
$remoteHands = !empty($_POST['remote_hands']);
|
||||||
|
|
||||||
|
// Build email body
|
||||||
|
$body = "Uusi tarjouspyyntö konesaliturku.fi:n kautta\n";
|
||||||
|
$body .= str_repeat('=', 50) . "\n\n";
|
||||||
|
|
||||||
|
$body .= "YHTEYSTIEDOT\n";
|
||||||
|
$body .= "Nimi: $name\n";
|
||||||
|
if ($company) $body .= "Yritys: $company\n";
|
||||||
|
$body .= "Sähköposti: $email\n";
|
||||||
|
if ($phone) $body .= "Puhelin: $phone\n";
|
||||||
|
$body .= "\n";
|
||||||
|
|
||||||
|
// Laitepaikat
|
||||||
|
$body .= "LAITEPAIKAT\n";
|
||||||
|
if ($units1u) $body .= " 1U laitepaikka: {$units1u} kpl (á €49/kk)\n";
|
||||||
|
if ($units2u) $body .= " 2U laitepaikka: {$units2u} kpl (á €79/kk)\n";
|
||||||
|
if ($units4u) $body .= " 4U laitepaikka: {$units4u} kpl (á €139/kk)\n";
|
||||||
|
if ($unitsRack) $body .= " Kokokaappi (42U): {$unitsRack} kpl\n";
|
||||||
|
if (!$units1u && !$units2u && !$units4u && !$unitsRack) $body .= " Ei valittu\n";
|
||||||
|
$body .= "\n";
|
||||||
|
|
||||||
|
// Yhteys
|
||||||
|
$body .= "YHTEYS\n";
|
||||||
|
$connLabels = [
|
||||||
|
'0' => '1 Gbit/s jaettu (sis. hintaan)',
|
||||||
|
'99' => '1 Gbit/s dedicated (€99/kk)',
|
||||||
|
'299' => '10 Gbit/s dedicated (€299/kk)',
|
||||||
|
'custom' => '100 Gbit/s (räätälöity)',
|
||||||
|
];
|
||||||
|
$body .= " Nopeus: " . ($connLabels[$connection] ?? 'Ei valittu') . "\n";
|
||||||
|
if ($redundantPort) $body .= " Varmennettu portti: Kyllä (€10/kk)\n";
|
||||||
|
if ($bgp === 20) $body .= " BGP-reititys: Default-route (€20/kk)\n";
|
||||||
|
if ($bgp === 50) $body .= " BGP-reititys: Koko internet (€50/kk)\n";
|
||||||
|
$body .= "\n";
|
||||||
|
|
||||||
|
// VPN
|
||||||
|
$vpnLabels = [
|
||||||
|
'0' => null,
|
||||||
|
'95' => '1G Site-to-Site (alk. €95/kk)',
|
||||||
|
'129' => '10G Site-to-Site (alk. €129/kk)',
|
||||||
|
'custom' => 'Dedicated L2/MPLS (räätälöity)',
|
||||||
|
];
|
||||||
|
if ($vpn !== '0' && isset($vpnLabels[$vpn])) {
|
||||||
|
$body .= "VPN\n";
|
||||||
|
$body .= " " . $vpnLabels[$vpn] . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lisäpalvelut
|
||||||
|
$addons = [];
|
||||||
|
if ($anycastDns) $addons[] = 'Anycast DNS (€19/kk)';
|
||||||
|
if ($blockStorage) $addons[] = 'Blokkitason storage (alk. €29/kk)';
|
||||||
|
if ($s3Storage) $addons[] = 'S3-levypinta (alk. €19/kk)';
|
||||||
|
if ($remoteHands) $addons[] = 'Remote Hands (tuntiveloitus)';
|
||||||
|
if ($addons) {
|
||||||
|
$body .= "LISÄPALVELUT\n";
|
||||||
|
foreach ($addons as $a) $body .= " $a\n";
|
||||||
|
$body .= "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($message) {
|
||||||
|
$body .= "VIESTI\n$message\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$body .= str_repeat('-', 50) . "\n";
|
||||||
|
$body .= "IP: $ip | Aika: " . date('d.m.Y H:i:s') . "\n";
|
||||||
|
|
||||||
|
// Save to file
|
||||||
|
$quoteFile = __DIR__ . '/data/quotes.json';
|
||||||
|
$quotes = [];
|
||||||
|
if (file_exists($quoteFile)) {
|
||||||
|
$quotes = json_decode(file_get_contents($quoteFile), true) ?: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$quotes[] = [
|
||||||
|
'id' => uniqid(),
|
||||||
|
'name' => $name,
|
||||||
|
'company' => $company,
|
||||||
|
'email' => $email,
|
||||||
|
'phone' => $phone,
|
||||||
|
'units_1u' => $units1u,
|
||||||
|
'units_2u' => $units2u,
|
||||||
|
'units_4u' => $units4u,
|
||||||
|
'units_rack' => $unitsRack,
|
||||||
|
'connection' => $connection,
|
||||||
|
'redundant_port' => $redundantPort,
|
||||||
|
'bgp' => $bgp,
|
||||||
|
'vpn' => $vpn,
|
||||||
|
'anycast_dns' => $anycastDns,
|
||||||
|
'block_storage' => $blockStorage,
|
||||||
|
's3_storage' => $s3Storage,
|
||||||
|
'remote_hands' => $remoteHands,
|
||||||
|
'message' => $message,
|
||||||
|
'ip' => $ip,
|
||||||
|
'created_at' => date('Y-m-d H:i:s')
|
||||||
|
];
|
||||||
|
|
||||||
|
$dir = dirname($quoteFile);
|
||||||
|
if (!is_dir($dir)) {
|
||||||
|
mkdir($dir, 0755, true);
|
||||||
|
}
|
||||||
|
file_put_contents($quoteFile, json_encode($quotes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||||
|
|
||||||
|
// Send email
|
||||||
|
$to = 'support@konesaliturku.fi';
|
||||||
|
$subject = 'Tarjouspyyntö: ' . $name . ($company ? " ($company)" : '');
|
||||||
|
$headers = "From: noreply@konesaliturku.fi\r\n";
|
||||||
|
$headers .= "Reply-To: $email\r\n";
|
||||||
|
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
|
||||||
|
|
||||||
|
@mail($to, $subject, $body, $headers);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
echo json_encode(['error' => 'Unknown action']);
|
echo json_encode(['error' => 'Unknown action']);
|
||||||
|
|||||||
@@ -410,16 +410,36 @@
|
|||||||
const honeypot = form.querySelector('[name="website"]');
|
const honeypot = form.querySelector('[name="website"]');
|
||||||
if (honeypot && honeypot.value) return;
|
if (honeypot && honeypot.value) return;
|
||||||
|
|
||||||
|
const submitBtn = form.querySelector('.btn-submit');
|
||||||
|
submitBtn.disabled = true;
|
||||||
status.textContent = 'Lähetetään...';
|
status.textContent = 'Lähetetään...';
|
||||||
status.className = 'form-status';
|
status.className = 'form-status';
|
||||||
|
|
||||||
// Simulate send
|
const formData = new FormData(form);
|
||||||
setTimeout(function() {
|
|
||||||
status.textContent = 'Kiitos! Tarjouspyyntösi on vastaanotettu. Otamme yhteyttä vuorokauden sisällä.';
|
fetch('api.php?action=quote', {
|
||||||
status.className = 'form-status form-status-success';
|
method: 'POST',
|
||||||
form.reset();
|
body: formData
|
||||||
calculate();
|
})
|
||||||
}, 1000);
|
.then(function(res) { return res.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.error) {
|
||||||
|
status.textContent = data.error;
|
||||||
|
status.className = 'form-status form-status-error';
|
||||||
|
} else {
|
||||||
|
status.textContent = 'Kiitos! Tarjouspyyntösi on vastaanotettu. Otamme yhteyttä vuorokauden sisällä.';
|
||||||
|
status.className = 'form-status form-status-success';
|
||||||
|
form.reset();
|
||||||
|
calculate();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
status.textContent = 'Virhe lähetyksessä. Yritä uudelleen tai ota yhteyttä sähköpostilla.';
|
||||||
|
status.className = 'form-status form-status-error';
|
||||||
|
})
|
||||||
|
.finally(function() {
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user