$ok, 'message' => $message], JSON_UNESCAPED_UNICODE); } else { if ($ok) { header('Location: /gracias.html', true, 303); } else { header('Content-Type: text/plain; charset=UTF-8'); echo $message; } } exit; } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { respond(false, 'Método no permitido.', 405); } $honeypot = trim((string)($_POST['website'] ?? '')); if ($honeypot !== '') { respond(true, 'Mensaje enviado correctamente.'); } $startedAt = (int)($_POST['started_at'] ?? 0); if ($startedAt > 0 && time() - $startedAt < 4) { respond(false, 'El formulario se ha enviado demasiado rápido. Inténtalo de nuevo.', 400); } $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; $rateKey = hash('sha256', $ip . '|' . date('Y-m-d-H')); $rateFile = sys_get_temp_dir() . '/riano_rate_' . $rateKey; $count = is_file($rateFile) ? (int)file_get_contents($rateFile) : 0; if ($count >= 6) { respond(false, 'Demasiados envíos en poco tiempo. Inténtalo más tarde.', 429); } file_put_contents($rateFile, (string)($count + 1), LOCK_EX); function clean(string $value, int $max = 1200): string { $value = trim($value); $value = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $value) ?? ''; $value = strip_tags($value); return mb_substr($value, 0, $max); } function header_value(string $value): string { return str_replace(["\r", "\n"], ' ', trim($value)); } $name = clean((string)($_POST['name'] ?? ''), 120); $email = clean((string)($_POST['email'] ?? ''), 180); $phone = clean((string)($_POST['phone'] ?? ''), 80); $business = clean((string)($_POST['business'] ?? ''), 180); $category = clean((string)($_POST['category'] ?? ''), 120); $message = clean((string)($_POST['message'] ?? ''), 2500); $context = clean((string)($_POST['form_context'] ?? 'contacto'), 80); $sourceUrl = filter_var((string)($_POST['source_url'] ?? ''), FILTER_SANITIZE_URL); $privacy = (string)($_POST['privacy'] ?? ''); if ($name === '' || $email === '' || $message === '' || $privacy !== '1') { respond(false, 'Faltan campos obligatorios.', 400); } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { respond(false, 'El email no parece válido.', 400); } $allowedCategories = [ 'Sugerencia o corrección', 'Negocio local', 'Colaboración', 'Otro', 'Alojamiento', 'Restaurante / bar / cafetería', 'Turismo activo / guía', 'Producto local' ]; if ($category !== '' && !in_array($category, $allowedCategories, true)) { respond(false, 'Categoría no válida.', 400); } $to = getenv('RIANO_CONTACT_TO') ?: 'webmaster@cabral.es'; $from = getenv('RIANO_CONTACT_FROM') ?: 'webmaster@cabral.es'; $siteName = 'Riaño.com'; $subjectBase = $context === 'negocios' ? 'Solicitud negocio local' : 'Contacto'; $subjectDetail = $business !== '' ? $business : $name; $subject = sprintf('[Riaño.com] %s - %s', $subjectBase, $subjectDetail); $encodedSubject = '=?UTF-8?B?' . base64_encode($subject) . '?='; $bodyLines = [ 'Nueva solicitud desde Riaño.com', '', 'Contexto: ' . $context, 'Nombre: ' . $name, 'Email: ' . $email, 'Teléfono: ' . ($phone ?: 'No indicado'), 'Negocio: ' . ($business ?: 'No indicado'), 'Categoría: ' . ($category ?: 'No indicada'), 'URL origen: ' . ($sourceUrl ?: 'No indicada'), '', 'Mensaje:', $message, '', '---', 'Enviado desde el formulario de Riaño.com.' ]; $body = implode("\n", $bodyLines); $headers = []; $headers[] = 'MIME-Version: 1.0'; $headers[] = 'Content-Type: text/plain; charset=UTF-8'; $headers[] = 'Content-Transfer-Encoding: 8bit'; $headers[] = 'From: =?UTF-8?B?' . base64_encode($siteName) . '?= <' . $from . '>'; $headers[] = 'Reply-To: ' . header_value($name) . ' <' . header_value($email) . '>'; $headers[] = 'Sender: ' . $from; $headers[] = 'X-Mailer: PHP/' . phpversion(); $sent = mail($to, $encodedSubject, $body, implode("\r\n", $headers)); if (!$sent) { respond(false, 'No se ha podido enviar el mensaje. Inténtalo de nuevo o escribe por email.', 500); } respond(true, 'Mensaje enviado correctamente. Gracias por contactar con Riaño.com.');