false, 'error' => 'Virheellinen pyyntö']); exit; } // Rate limiting (yksinkertainen, IP-pohjainen) $rateLimitDir = __DIR__ . '/data'; if (!is_dir($rateLimitDir)) { mkdir($rateLimitDir, 0755, true); } $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown'; $rateLimitFile = $rateLimitDir . '/ratelimit_' . md5($ip) . '.txt'; $now = time(); if (file_exists($rateLimitFile)) { $lastSent = (int) file_get_contents($rateLimitFile); if ($now - $lastSent < 60) { http_response_code(429); echo json_encode(['success' => false, 'error' => 'Odota hetki ennen uutta lähetystä']); exit; } } // Honeypot-kenttä (botisuoja) if (!empty($_POST['website'])) { http_response_code(200); echo json_encode(['success' => true]); exit; } // Kentät $company = trim($_POST['company'] ?? ''); $email = trim($_POST['email'] ?? ''); $address = trim($_POST['address'] ?? ''); $city = trim($_POST['city'] ?? ''); $message = trim($_POST['message'] ?? ''); // Validointi if (empty($company) || empty($email) || empty($address) || empty($city)) { http_response_code(400); echo json_encode(['success' => false, 'error' => 'Täytä kaikki pakolliset kentät']); exit; } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { http_response_code(400); echo json_encode(['success' => false, 'error' => 'Tarkista sähköpostiosoite']); exit; } // Sanitointi $company = htmlspecialchars($company, ENT_QUOTES, 'UTF-8'); $email = htmlspecialchars($email, ENT_QUOTES, 'UTF-8'); $address = htmlspecialchars($address, ENT_QUOTES, 'UTF-8'); $city = htmlspecialchars($city, ENT_QUOTES, 'UTF-8'); $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); // Sähköpostin sisältö $to = 'asiakaspalvelu@cuitunet.fi'; $subject = "Saatavuuskysely: $company – $address, $city"; $body = "Uusi saatavuuskysely cuitunet.fi-sivustolta\n"; $body .= "=========================================\n\n"; $body .= "Yritys: $company\n"; $body .= "Sähköposti: $email\n"; $body .= "Osoite: $address\n"; $body .= "Kaupunki: $city\n"; if (!empty($message)) { $body .= "Lisätiedot: $message\n"; } $body .= "\n-----------------------------------------\n"; $body .= "Lähetetty: " . date('d.m.Y H:i') . "\n"; $body .= "IP: $ip\n"; $headers = "From: sivusto@cuitunet.fi\r\n"; $headers .= "Reply-To: $email\r\n"; $headers .= "Content-Type: text/plain; charset=UTF-8\r\n"; $headers .= "X-Mailer: Cuitunet-Web\r\n"; // SMTP-lähetys mail2.fi:n kautta (STARTTLS + auth) function sendViaSMTP(string $to, string $subject, string $body, string $replyTo): string { $smtpHost = 'smtp.mail2.fi'; $smtpPort = 587; $smtpUser = 'sivusto@cuitunet.fi'; $smtpPass = 'Passus123!'; $fromEmail = 'sivusto@cuitunet.fi'; $fromName = 'Cuitunet Saatavuuskysely'; $hostname = 'cuitunet.fi'; $sock = @fsockopen($smtpHost, $smtpPort, $errno, $errstr, 10); if (!$sock) return "SMTP-yhteys epäonnistui: $errstr ($errno)"; $resp = fgets($sock, 512); if (substr($resp, 0, 3) !== '220') { fclose($sock); return "SMTP hylkäsi: $resp"; } // EHLO fwrite($sock, "EHLO $hostname\r\n"); $resp = fgets($sock, 512); while (substr($resp, 3, 1) === '-') { $resp = fgets($sock, 512); } // STARTTLS fwrite($sock, "STARTTLS\r\n"); $resp = fgets($sock, 512); if (substr($resp, 0, 3) !== '220') { fclose($sock); return "STARTTLS epäonnistui: $resp"; } if (!stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT)) { fclose($sock); return "TLS handshake epäonnistui"; } // EHLO uudelleen TLS:n jälkeen fwrite($sock, "EHLO $hostname\r\n"); $resp = fgets($sock, 512); while (substr($resp, 3, 1) === '-') { $resp = fgets($sock, 512); } // AUTH LOGIN fwrite($sock, "AUTH LOGIN\r\n"); $resp = fgets($sock, 512); if (substr($resp, 0, 3) !== '334') { fclose($sock); return "AUTH ei tuettu: $resp"; } fwrite($sock, base64_encode($smtpUser) . "\r\n"); $resp = fgets($sock, 512); if (substr($resp, 0, 3) !== '334') { fclose($sock); return "Käyttäjänimi hylätty: $resp"; } fwrite($sock, base64_encode($smtpPass) . "\r\n"); $resp = fgets($sock, 512); if (substr($resp, 0, 3) !== '235') { fclose($sock); return "Kirjautuminen epäonnistui: $resp"; } // MAIL FROM / RCPT TO / DATA fwrite($sock, "MAIL FROM:<$fromEmail>\r\n"); $resp = fgets($sock, 512); if ($resp[0] !== '2') { fclose($sock); return "MAIL FROM hylätty: $resp"; } fwrite($sock, "RCPT TO:<$to>\r\n"); $resp = fgets($sock, 512); if ($resp[0] !== '2') { fclose($sock); return "RCPT TO hylätty: $resp"; } fwrite($sock, "DATA\r\n"); $resp = fgets($sock, 512); if (substr($resp, 0, 3) !== '354') { fclose($sock); return "DATA hylätty: $resp"; } // Viesti $msg = "From: $fromName <$fromEmail>\r\n"; $msg .= "To: $to\r\n"; $msg .= "Reply-To: $replyTo\r\n"; $msg .= "Subject: $subject\r\n"; $msg .= "Content-Type: text/plain; charset=UTF-8\r\n"; $msg .= "Date: " . date('r') . "\r\n"; $msg .= "Message-ID: <" . uniqid('cuitunet-') . "@$hostname>\r\n"; $msg .= "\r\n"; $msg .= str_replace("\n.", "\n..", $body); $msg .= "\r\n.\r\n"; fwrite($sock, $msg); $resp = fgets($sock, 512); fwrite($sock, "QUIT\r\n"); fclose($sock); return (substr($resp, 0, 3) === '250') ? '' : "Lähetys epäonnistui: $resp"; } $smtpError = sendViaSMTP($to, $subject, $body, $email); if (empty($smtpError)) { // Tallenna rate limit file_put_contents($rateLimitFile, $now); // Tallenna kopio kyselyistä $logFile = $rateLimitDir . '/kyselyt.log'; $logEntry = date('Y-m-d H:i:s') . " | $company | $email | $address, $city | $message\n"; file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX); echo json_encode(['success' => true]); } else { error_log("cuitunet.fi send.php SMTP error: $smtpError"); http_response_code(500); echo json_encode(['success' => false, 'error' => 'Viestin lähetys epäonnistui. Yritä myöhemmin uudelleen.']); }