Загрузил проект на гит сурс
This commit is contained in:
+206
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
header("Content-Type: application/json; charset=UTF-8");
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
http_response_code(405);
|
||||
echo json_encode([
|
||||
"ok" => false,
|
||||
"message" => "Метод не поддерживается",
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function respondError(string $message, int $code = 400): void
|
||||
{
|
||||
http_response_code($code);
|
||||
echo json_encode([
|
||||
"ok" => false,
|
||||
"message" => $message,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function sanitizeInput(string $value): string
|
||||
{
|
||||
$clean = trim($value);
|
||||
return preg_replace("/[\\x00-\\x1F\\x7F]/u", "", $clean) ?? "";
|
||||
}
|
||||
|
||||
function respondSuccess(): void
|
||||
{
|
||||
echo json_encode([
|
||||
"ok" => true,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function loadRateLimitState(string $filePath): array
|
||||
{
|
||||
if (!is_file($filePath)) {
|
||||
return [];
|
||||
}
|
||||
$raw = file_get_contents($filePath);
|
||||
if ($raw === false || $raw === "") {
|
||||
return [];
|
||||
}
|
||||
$data = json_decode($raw, true);
|
||||
return is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
function storeRateLimitState(string $filePath, array $state): void
|
||||
{
|
||||
$encoded = json_encode($state, JSON_UNESCAPED_UNICODE);
|
||||
if ($encoded === false) {
|
||||
return;
|
||||
}
|
||||
@file_put_contents($filePath, $encoded, LOCK_EX);
|
||||
}
|
||||
|
||||
function isRateLimited(string $ip, int $nowTs): bool
|
||||
{
|
||||
$limitWindowSeconds = 10 * 60; // 10 минут
|
||||
$limitAttempts = 8;
|
||||
$rateFile = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . "frieze_spb_rate_limit.json";
|
||||
|
||||
$state = loadRateLimitState($rateFile);
|
||||
$freshState = [];
|
||||
|
||||
foreach ($state as $storedIp => $timestamps) {
|
||||
if (!is_array($timestamps)) {
|
||||
continue;
|
||||
}
|
||||
$validTs = [];
|
||||
foreach ($timestamps as $ts) {
|
||||
$intTs = (int)$ts;
|
||||
if ($intTs >= $nowTs - $limitWindowSeconds) {
|
||||
$validTs[] = $intTs;
|
||||
}
|
||||
}
|
||||
if ($validTs) {
|
||||
$freshState[$storedIp] = $validTs;
|
||||
}
|
||||
}
|
||||
|
||||
$currentIpHits = $freshState[$ip] ?? [];
|
||||
if (count($currentIpHits) >= $limitAttempts) {
|
||||
storeRateLimitState($rateFile, $freshState);
|
||||
return true;
|
||||
}
|
||||
|
||||
$currentIpHits[] = $nowTs;
|
||||
$freshState[$ip] = $currentIpHits;
|
||||
storeRateLimitState($rateFile, $freshState);
|
||||
return false;
|
||||
}
|
||||
|
||||
$name = sanitizeInput((string)($_POST["name"] ?? ""));
|
||||
$phoneRaw = sanitizeInput((string)($_POST["phone"] ?? ""));
|
||||
$consent = (string)($_POST["consent"] ?? "");
|
||||
$honeypot = sanitizeInput((string)($_POST["contact_fax"] ?? ($_POST["website"] ?? "")));
|
||||
$startedAtRaw = sanitizeInput((string)($_POST["started_at"] ?? ""));
|
||||
|
||||
if ($honeypot !== "") {
|
||||
respondError("Не удалось отправить заявку. Пожалуйста, попробуйте еще раз.", 400);
|
||||
}
|
||||
|
||||
$nowTs = time();
|
||||
$formMinFillSeconds = 0.4;
|
||||
$startedAtMs = (int)$startedAtRaw;
|
||||
if ($startedAtMs > 0) {
|
||||
$elapsedSeconds = ((int)floor(microtime(true) * 1000) - $startedAtMs) / 1000;
|
||||
if ($elapsedSeconds < $formMinFillSeconds) {
|
||||
respondError("Слишком быстрая отправка формы. Попробуйте еще раз.", 429);
|
||||
}
|
||||
}
|
||||
|
||||
$clientIp = (string)($_SERVER["REMOTE_ADDR"] ?? "unknown");
|
||||
if (isRateLimited($clientIp, $nowTs)) {
|
||||
respondError("Слишком много заявок за короткое время. Повторите попытку позже.", 429);
|
||||
}
|
||||
|
||||
if ($name === "") {
|
||||
respondError("Укажите имя");
|
||||
}
|
||||
|
||||
// Нормализуем имя: убираем лишние пробелы внутри.
|
||||
$name = preg_replace("/\\s+/u", " ", $name) ?? $name;
|
||||
|
||||
if (mb_strlen($name) < 2 || mb_strlen($name) > 80) {
|
||||
respondError("Имя должно быть от 2 до 80 символов");
|
||||
}
|
||||
|
||||
if (!preg_match("/^[\\p{L}\\s-]+$/u", $name)) {
|
||||
respondError("Имя может содержать только буквы, пробелы и дефис");
|
||||
}
|
||||
|
||||
$phoneDigits = preg_replace("/\\D+/", "", $phoneRaw) ?? "";
|
||||
if (strlen($phoneDigits) !== 11 || strpos($phoneDigits, "7") !== 0) {
|
||||
respondError("Укажите корректный телефон");
|
||||
}
|
||||
|
||||
if ($consent !== "1") {
|
||||
respondError("Необходимо согласие на обработку данных");
|
||||
}
|
||||
|
||||
// Укажите email в файле submit-config.php (предпочтительно для REG.RU)
|
||||
// или в переменной окружения FORM_RECIPIENT_EMAIL.
|
||||
$recipientEmail = "";
|
||||
$senderEmail = "";
|
||||
$configFile = __DIR__ . "/submit-config.php";
|
||||
if (is_file($configFile)) {
|
||||
require $configFile;
|
||||
}
|
||||
|
||||
if ($recipientEmail === "") {
|
||||
$recipientEmail = getenv("FORM_RECIPIENT_EMAIL") ?: "you@example.com";
|
||||
}
|
||||
|
||||
if (substr($recipientEmail, -11) === "@example.com") {
|
||||
respondError("Не настроен email получателя заявок. Укажите адрес в submit-config.php.", 500);
|
||||
}
|
||||
|
||||
$host = strtolower((string)($_SERVER["HTTP_HOST"] ?? "frieze-spb.ru"));
|
||||
$host = preg_replace("/:\\d+$/", "", $host) ?? "frieze-spb.ru";
|
||||
$host = preg_replace("/[^a-z0-9\\.-]/", "", $host) ?? "frieze-spb.ru";
|
||||
if ($host === "") {
|
||||
$host = "frieze-spb.ru";
|
||||
}
|
||||
$defaultSenderEmail = "noreply@" . $host;
|
||||
$fromEmail = $senderEmail !== "" ? $senderEmail : $defaultSenderEmail;
|
||||
if (!filter_var($fromEmail, FILTER_VALIDATE_EMAIL)) {
|
||||
$fromEmail = $defaultSenderEmail;
|
||||
}
|
||||
|
||||
$subject = "Новая заявка с сайта frieze-spb.ru";
|
||||
$encodedSubject = "=?UTF-8?B?" . base64_encode($subject) . "?=";
|
||||
|
||||
$messageLines = [
|
||||
"Новая заявка с сайта",
|
||||
"",
|
||||
"Имя: " . $name,
|
||||
"Телефон: " . $phoneRaw,
|
||||
"Телефон (цифры): +" . $phoneDigits,
|
||||
"Дата/время: " . date("d.m.Y H:i:s"),
|
||||
"IP: " . (string)($_SERVER["REMOTE_ADDR"] ?? "не определен"),
|
||||
"User-Agent: " . (string)($_SERVER["HTTP_USER_AGENT"] ?? "не определен"),
|
||||
];
|
||||
|
||||
$body = implode("\r\n", $messageLines);
|
||||
|
||||
$headers = [
|
||||
"MIME-Version: 1.0",
|
||||
"Content-Type: text/plain; charset=UTF-8",
|
||||
"From: Frieze Site <" . $fromEmail . ">",
|
||||
"Reply-To: " . $recipientEmail,
|
||||
"X-Mailer: PHP/" . PHP_VERSION,
|
||||
];
|
||||
|
||||
$sent = mail($recipientEmail, $encodedSubject, $body, implode("\r\n", $headers), "-f" . $fromEmail);
|
||||
|
||||
if (!$sent) {
|
||||
respondError("Не удалось отправить заявку. Попробуйте позже или позвоните по телефону.", 500);
|
||||
}
|
||||
|
||||
respondSuccess();
|
||||
Reference in New Issue
Block a user