Make drone serial number field mandatory in trip form
- Added required validation for bvs_number field in send_plan.php - Updated form label to show asterisk (*) indicating required field - Implemented file attachment support in email notifications (multipart MIME) - Files are now temporarily saved and automatically deleted after email is sent
This commit is contained in:
+2
-2
@@ -192,8 +192,8 @@ disableComments = true
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="bvs_number"><strong>Учётный номер для БВС от 0,15 кг или серийный номер для БВС до 0,15 кг</strong></label>
|
<label for="bvs_number"><strong>Учётный номер для БВС от 0,15 кг или серийный номер для БВС до 0,15 кг *</strong></label>
|
||||||
<textarea id="bvs_number" name="bvs_number" placeholder="Укажите учётный номер для БВС от 0,15 кг или серийный номер для БВС до 0,15 кг"></textarea>
|
<textarea id="bvs_number" name="bvs_number" placeholder="Укажите учётный номер для БВС от 0,15 кг или серийный номер для БВС до 0,15 кг" required></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
+134
-4
@@ -59,22 +59,32 @@ function get_forms_settings() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Простое шифрование данных для безопасного хранения
|
* Простое шифрование данных для безопасного хранения
|
||||||
|
* Совместимо с Python Crypto.Cipher.AES + unpad
|
||||||
*/
|
*/
|
||||||
function encrypt_data($data, $key) {
|
function encrypt_data($data, $key) {
|
||||||
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
|
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||||
$iv = random_bytes(16);
|
$iv = random_bytes(16);
|
||||||
$encrypted = openssl_encrypt($json, 'AES-256-CBC', hash('sha256', $key), 0, $iv);
|
|
||||||
return base64_encode($iv . $encrypted);
|
// openssl_encrypt с параметром 0 сам добавляет PKCS7 padding и возвращает base64
|
||||||
|
$encrypted_b64 = openssl_encrypt($json, 'AES-256-CBC', hash('sha256', $key), 0, $iv);
|
||||||
|
// Декодируем base64 чтобы получить бинарные данные
|
||||||
|
$encrypted_raw = base64_decode($encrypted_b64);
|
||||||
|
// Добавляем IV в начало и кодируем все вместе
|
||||||
|
return base64_encode($iv . $encrypted_raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Расшифровка данных
|
* Расшифровка данных
|
||||||
|
* Совместимо с Python Crypto.Cipher.AES + unpad
|
||||||
*/
|
*/
|
||||||
function decrypt_data($encrypted_data, $key) {
|
function decrypt_data($encrypted_data, $key) {
|
||||||
$data = base64_decode($encrypted_data);
|
$data = base64_decode($encrypted_data);
|
||||||
$iv = substr($data, 0, 16);
|
$iv = substr($data, 0, 16);
|
||||||
$encrypted = substr($data, 16);
|
$encrypted_raw = substr($data, 16);
|
||||||
$decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', hash('sha256', $key), 0, $iv);
|
// Кодируем обратно в base64 для openssl_decrypt
|
||||||
|
$encrypted_b64 = base64_encode($encrypted_raw);
|
||||||
|
// openssl_decrypt с параметром 0 сам убирает PKCS7 padding
|
||||||
|
$decrypted = openssl_decrypt($encrypted_b64, 'AES-256-CBC', hash('sha256', $key), 0, $iv);
|
||||||
return json_decode($decrypted, true);
|
return json_decode($decrypted, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +218,126 @@ function send_telegram_notification($form_data, $form_type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отправка уведомления на Email через msmtp с поддержкой файлов
|
||||||
|
*/
|
||||||
|
function send_email_notification($form_data, $form_type) {
|
||||||
|
$settings = get_forms_settings();
|
||||||
|
|
||||||
|
if (!$settings['send_email']) {
|
||||||
|
return true; // Отправка email отключена
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем admin email из .env
|
||||||
|
$admin_email = getenv('ADMIN_EMAIL') ?: 'admin@example.com';
|
||||||
|
$from_email = getenv('SMTP_FROM_EMAIL') ?: getenv('SMTP_USERNAME') ?: 'noreply@yourdomain.com';
|
||||||
|
$from_name = getenv('SMTP_FROM_NAME') ?: 'PTP Robot';
|
||||||
|
|
||||||
|
// Формируем тему письма
|
||||||
|
$subject = ($form_type === 'plan')
|
||||||
|
? '🎫 Новая заявка на поездку - ' . $form_data['name']
|
||||||
|
: '❓ Новый вопрос - ' . ($form_data['subject'] ?? 'Без темы');
|
||||||
|
|
||||||
|
// Формируем тело письма
|
||||||
|
$message = "Новая заявка с сайта\n\n";
|
||||||
|
$message .= "Тип: " . ($form_type === 'plan' ? 'Заявка на поездку' : 'Вопрос') . "\n";
|
||||||
|
$message .= "Время: " . date('Y-m-d H:i:s') . "\n\n";
|
||||||
|
|
||||||
|
$message .= "=== ДАННЫЕ ЗАЯВИТЕЛЯ ===\n";
|
||||||
|
$message .= "Имя: " . $form_data['name'] . "\n";
|
||||||
|
$message .= "Email: " . $form_data['email'] . "\n";
|
||||||
|
|
||||||
|
if ($form_type === 'plan') {
|
||||||
|
$message .= "Телефон: " . ($form_data['phone'] ?: 'не указан') . "\n";
|
||||||
|
$message .= "Telegram: " . ($form_data['telegram'] ?: 'не указан') . "\n";
|
||||||
|
$message .= "Поездка: " . ($form_data['trip_period'] ?: 'не выбрана') . "\n";
|
||||||
|
$message .= "БВС/Направление: " . ($form_data['bvs_number'] ?: 'не указано') . "\n";
|
||||||
|
} else {
|
||||||
|
if (!empty($form_data['telegram'])) {
|
||||||
|
$message .= "Telegram: " . $form_data['telegram'] . "\n";
|
||||||
|
}
|
||||||
|
if (!empty($form_data['phone'])) {
|
||||||
|
$message .= "Телефон: " . $form_data['phone'] . "\n";
|
||||||
|
}
|
||||||
|
$message .= "Тема: " . $form_data['subject'] . "\n";
|
||||||
|
$message .= "\n=== СООБЩЕНИЕ ===\n";
|
||||||
|
$message .= $form_data['message'] . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем наличие файла для отправки
|
||||||
|
$attachment_file = $form_data['bvs_file_path'] ?? null;
|
||||||
|
$has_attachment = $attachment_file && file_exists($attachment_file);
|
||||||
|
|
||||||
|
// Создаем boundary для multipart письма если есть файл
|
||||||
|
$boundary = "----=_Part_" . md5(time() . rand());
|
||||||
|
|
||||||
|
if ($has_attachment) {
|
||||||
|
// Заголовки письма с файлом (multipart)
|
||||||
|
$headers = "From: $from_name <$from_email>\r\n";
|
||||||
|
$headers .= "Reply-To: " . $form_data['email'] . "\r\n";
|
||||||
|
$headers .= "MIME-Version: 1.0\r\n";
|
||||||
|
$headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";
|
||||||
|
$headers .= "X-Mailer: PHP/" . phpversion();
|
||||||
|
|
||||||
|
// Формируем multipart тело письма
|
||||||
|
$multipart_message = "--$boundary\r\n";
|
||||||
|
$multipart_message .= "Content-Type: text/plain; charset=UTF-8\r\n";
|
||||||
|
$multipart_message .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
|
||||||
|
$multipart_message .= $message . "\r\n";
|
||||||
|
|
||||||
|
// Добавляем файл
|
||||||
|
$file_content = file_get_contents($attachment_file);
|
||||||
|
$file_name = basename($attachment_file);
|
||||||
|
// Извлекаем оригинальное имя файла (после bvs_)
|
||||||
|
if (preg_match('/bvs_\w+_(.+)$/', $file_name, $matches)) {
|
||||||
|
$file_name = $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$multipart_message .= "--$boundary\r\n";
|
||||||
|
$multipart_message .= "Content-Type: application/pdf; name=\"$file_name\"\r\n";
|
||||||
|
$multipart_message .= "Content-Transfer-Encoding: base64\r\n";
|
||||||
|
$multipart_message .= "Content-Disposition: attachment; filename=\"$file_name\"\r\n\r\n";
|
||||||
|
$multipart_message .= chunk_split(base64_encode($file_content)) . "\r\n";
|
||||||
|
|
||||||
|
$multipart_message .= "--$boundary--\r\n";
|
||||||
|
|
||||||
|
$email_message = $multipart_message;
|
||||||
|
} else {
|
||||||
|
// Заголовки письма без файла
|
||||||
|
$headers = "From: $from_name <$from_email>\r\n";
|
||||||
|
$headers .= "Reply-To: " . $form_data['email'] . "\r\n";
|
||||||
|
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
|
||||||
|
$headers .= "X-Mailer: PHP/" . phpversion();
|
||||||
|
$email_message = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Отправка письма
|
||||||
|
try {
|
||||||
|
error_log("=== Attempting mail() ===");
|
||||||
|
error_log("To: $admin_email | From: $from_email | Subject: $subject | Has attachment: " . ($has_attachment ? 'YES' : 'NO'));
|
||||||
|
$result = mail($admin_email, $subject, $email_message, $headers);
|
||||||
|
error_log("mail() returned: " . ($result ? 'TRUE' : 'FALSE'));
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
error_log("Email отправлен успешно на: $admin_email");
|
||||||
|
|
||||||
|
// Удаляем временный файл после отправки
|
||||||
|
if ($has_attachment && file_exists($attachment_file)) {
|
||||||
|
unlink($attachment_file);
|
||||||
|
error_log("Временный файл удален: $attachment_file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
error_log("Ошибка отправки email на: $admin_email");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Исключение при отправке email: " . $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получение списка всех заявок (для Telegram бота)
|
* Получение списка всех заявок (для Telegram бота)
|
||||||
*/
|
*/
|
||||||
|
|||||||
+15
-3
@@ -16,8 +16,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$bvs_file = $_FILES['bvs_file'] ?? null;
|
$bvs_file = $_FILES['bvs_file'] ?? null;
|
||||||
|
|
||||||
// Валидация
|
// Валидация
|
||||||
if (empty($name) || empty($consent)) {
|
if (empty($name) || empty($consent) || empty($bvs_number)) {
|
||||||
$error = "Обязательные поля: Фамилия, имя, Согласие на обработку данных.";
|
$error = "Обязательные поля: Фамилия, имя, Учётный номер дрона, Согласие на обработку данных.";
|
||||||
} elseif (empty($phone)) {
|
} elseif (empty($phone)) {
|
||||||
$error = "Обязательное поле: Телефон.";
|
$error = "Обязательное поле: Телефон.";
|
||||||
} elseif (empty($email) && empty($telegram)) {
|
} elseif (empty($email) && empty($telegram)) {
|
||||||
@@ -38,6 +38,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($error)) {
|
if (!isset($error)) {
|
||||||
|
// Сохраняем загруженный файл во временную папку
|
||||||
|
$uploaded_file_path = null;
|
||||||
|
if ($bvs_file && $bvs_file['error'] === UPLOAD_ERR_OK) {
|
||||||
|
$upload_dir = sys_get_temp_dir() . '/ptp_forms_uploads/';
|
||||||
|
if (!is_dir($upload_dir)) {
|
||||||
|
mkdir($upload_dir, 0700, true);
|
||||||
|
}
|
||||||
|
$uploaded_file_path = $upload_dir . uniqid('bvs_') . '_' . basename($bvs_file['name']);
|
||||||
|
move_uploaded_file($bvs_file['tmp_name'], $uploaded_file_path);
|
||||||
|
}
|
||||||
|
|
||||||
// Подготавливаем данные заявки
|
// Подготавливаем данные заявки
|
||||||
$form_data = [
|
$form_data = [
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
@@ -47,7 +58,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
'bvs_number' => $bvs_number,
|
'bvs_number' => $bvs_number,
|
||||||
'trip_period' => $trip_period,
|
'trip_period' => $trip_period,
|
||||||
'consent' => $consent,
|
'consent' => $consent,
|
||||||
'bvs_file' => $bvs_file ? $bvs_file['name'] : ''
|
'bvs_file' => $bvs_file ? $bvs_file['name'] : '',
|
||||||
|
'bvs_file_path' => $uploaded_file_path
|
||||||
];
|
];
|
||||||
|
|
||||||
$success_messages = [];
|
$success_messages = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user