🔐 ЗАЩИТА:
- CSRF-токен с hash_equals()
- Проверка метода POST
- Валидация всех полей
- CAPTCHA (математическая)
- htmlspecialchars() + preg_replace() от XSS
- Белый список для post_type
- Ограничения длины (имя 2-50, текст 3-1000)
- Проверка ID поста > 0
- PDO подготовленные запросы
⚙️ ФУНКЦИИ:
- Приём AJAX-запросов
- JSON-ответы
- Сохранение в таблицу comments
- Запоминание имени автора в сессии
- Логирование ошибок в error_log
📤 ВОЗВРАЩАЕТ JSON:
- success: true/false
- message: текст ошибки или успеха
- comment: данные комментария (при успехе)
<?php
session_start();
header('Content-Type: application/json'); // Всегда возвращаем JSON
require __DIR__ . '/../includes/db.php';
// CSRF-токен: создаём, если нет
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// Проверка CSRF (защита от подделки запросов)
if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'Ошибка безопасности: неверный токен']);
exit;
}
// Проверка метода запроса
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'Метод не разрешен']);
exit;
}
// Валидация обязательных полей
$required = ['post_type', 'post_id', 'author', 'text', 'captcha'];
$missing = [];
foreach ($required as $field) {
if (empty($_POST[$field])) {
$missing[] = $field;
}
}
if (!empty($missing)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Обязательные поля: ' . implode(', ', $missing)]);
exit;
}
// Обработка и очистка данных
$post_type = ($_POST['post_type'] === 'code' || $_POST['post_type'] === 'article') ? $_POST['post_type'] : 'article';
$post_id = (int)$_POST['post_id'];
$author = trim($_POST['author']);
$text = trim($_POST['text']);
$captcha = (int)$_POST['captcha'];
// Проверка: ID поста должен быть положительным
if ($post_id <= 0) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Неверный ID поста']);
exit;
}
// Проверка длины имени
if (strlen($author) < 2 || strlen($author) > 50) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Имя должно быть от 2 до 50 символов']);
exit;
}
// Проверка длины комментария
if (strlen($text) < 3 || strlen($text) > 1000) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Комментарий должен быть от 3 до 1000 символов']);
exit;
}
// Проверка CAPTCHA
if (!isset($_SESSION['captcha_answer']) || $captcha !== (int)$_SESSION['captcha_answer']) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Неверная CAPTCHA']);
exit;
}
// Фильтрация опасных символов (дополнительный слой защиты)
$author = preg_replace('/[<>]/', '', $author);
$text = preg_replace('/[<>]/', '', $text);
// Экранирование перед сохранением в БД
$author_safe = htmlspecialchars($author, ENT_QUOTES, 'UTF-8');
$text_safe = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
// Сохранение комментария
try {
$stmt = $pdo->prepare("INSERT INTO comments (post_type, post_id, author, text, created_at) VALUES (?, ?, ?, ?, NOW())");
$stmt->execute([$post_type, $post_id, $author_safe, $text_safe]);
// Сохраняем имя автора в сессию для удобства
$_SESSION['comment_author'] = $author_safe;
// Удаляем CAPTCHA из сессии
unset($_SESSION['captcha_answer']);
echo json_encode([
'success' => true,
'message' => 'Комментарий успешно добавлен',
'comment' => [
'author' => $author_safe,
'text' => nl2br($text_safe),
'date' => date('d.m.Y H:i')
]
]);
exit;
} catch (PDOException $e) {
error_log('DB Error in add_comment.php: ' . $e->getMessage());
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Ошибка базы данных. Попробуйте позже.']);
exit;
}
?>
Комментарии
Пока нет комментариев. Будьте первым!