email = new EmailService(); } /** * POST /api/mktg-lead */ public function submit(): void { // Rate limit: 3 richieste / 10 min per IP $ip = $this->getClientIP(); $cacheFile = sys_get_temp_dir() . '/nis2_mktglead_' . md5($ip); $now = time(); $cache = file_exists($cacheFile) ? json_decode(file_get_contents($cacheFile), true) : ['requests' => []]; $cache['requests'] = array_filter($cache['requests'] ?? [], fn($t) => $t > ($now - 600)); if (count($cache['requests']) >= 3) { $this->jsonError('Troppe richieste. Riprova tra qualche minuto.', 429); return; } $cache['requests'][] = $now; file_put_contents($cacheFile, json_encode($cache)); // Input $body = $this->getJsonBody(); // Supporta sia campi IT (form NIS2) che campi EN (standard mktg) $name = trim($body['name'] ?? $body['nome'] ?? ''); $email = trim($body['email'] ?? ''); $phone = trim($body['phone'] ?? $body['telefono'] ?? ''); $company = trim($body['company'] ?? $body['azienda'] ?? ''); $role = trim($body['role'] ?? $body['tipo'] ?? ''); $size = trim($body['size'] ?? $body['n_dipendenti'] ?? ''); $interest = trim($body['product_interest'] ?? $body['interesse'] ?? ''); $notes = trim($body['notes'] ?? $body['messaggio'] ?? ''); $source = trim($body['source'] ?? self::SOURCE); // Validazione if (!$name || !$email || !$company) { $this->jsonError('Compila i campi obbligatori: nome, email, azienda.', 422); return; } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $this->jsonError('Indirizzo email non valido.', 422); return; } // Sanitize $name = htmlspecialchars($name, ENT_QUOTES, 'UTF-8'); $email = htmlspecialchars($email, ENT_QUOTES, 'UTF-8'); $phone = htmlspecialchars($phone, ENT_QUOTES, 'UTF-8'); $company = htmlspecialchars($company, ENT_QUOTES, 'UTF-8'); $role = htmlspecialchars($role, ENT_QUOTES, 'UTF-8'); $size = htmlspecialchars($size, ENT_QUOTES, 'UTF-8'); $interest = htmlspecialchars($interest, ENT_QUOTES, 'UTF-8'); $source = htmlspecialchars($source, ENT_QUOTES, 'UTF-8'); // Componi notes con campi aggiuntivi $noteParts = []; if ($role) $noteParts[] = "Ruolo: {$role}"; if ($size) $noteParts[] = "Dimensioni: {$size}"; if ($interest) $noteParts[] = "Interesse: {$interest}"; if ($notes) $noteParts[] = $notes; $fullNotes = implode(' | ', $noteParts); // Payload standard mktg $payload = [ 'name' => $name, 'email' => $email, 'phone' => $phone, 'company' => $company, 'product_interest' => $interest ?: self::PRODUCT, 'source' => $source, 'notes' => $fullNotes, ]; // 1. Prova webhook mktg.agile.software $webhookOk = $this->sendWebhook($payload); // 2. Fallback email se webhook fallisce if (!$webhookOk) { $this->sendFallbackEmail($payload, $ip); } $this->jsonSuccess(null, 'Richiesta inviata! Ti contatteremo entro 24 ore con il tuo codice di accesso.'); } private function sendWebhook(array $payload): bool { $ch = curl_init(self::WEBHOOK_URL); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-Webhook-Key: ' . self::WEBHOOK_KEY, ], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 8, CURLOPT_SSL_VERIFYPEER => true, ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error || $httpCode < 200 || $httpCode >= 300) { error_log("MktgLead webhook failed [{$httpCode}]: {$error}"); return false; } return true; } private function sendFallbackEmail(array $payload, string $ip): void { $date = date('d/m/Y H:i'); $rows = ''; $labels = [ 'name' => 'Nome', 'email' => 'Email', 'phone' => 'Telefono', 'company' => 'Azienda', 'product_interest' => 'Interesse', 'source' => 'Source', 'notes' => 'Note', ]; foreach ($labels as $key => $label) { $val = $payload[$key] ?? ''; if (!$val) continue; $rows .= "
Ricevuto il {$date} ยท IP: {$ip}
โ ๏ธ Webhook mktg.agile.software non raggiungibile โ lead salvato via email.
Genera il codice invito: licenseExt.html