Задать вопрос
  • Как добавить reCAPTCHA к форме PHPMailer?

    @shelepun
    Проблема в вашем коде заключается в том, что вы не объединяете проверку reCAPTCHA с процессом отправки письма. Вот исправленный вариант:
    <?php
    // Файлы phpmailer
    require 'phpmailer/PHPMailer.php';
    require 'phpmailer/SMTP.php';
    require 'phpmailer/Exception.php';
    
    // Инициализация массива данных для ответа
    $data = [];
    
    # проверка, что ошибки нет
    if (!error_get_last()) {
        // Проверка reCAPTCHA
        if(isset($_POST['token'])){
            $secretKey = '***'; // Ваш секретный ключ reCAPTCHA
            $token = $_POST['token'];
            $url = 'https://www.google.com/recaptcha/api/siteverify';
            
            // Используем cURL вместо file_get_contents для лучшей обработки ошибок
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
                'secret' => $secretKey,
                'response' => $token,
                'remoteip' => $_SERVER['REMOTE_ADDR']
            ));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $response = curl_exec($ch);
            curl_close($ch);
            
            $responseKeys = json_decode($response, true);
            
            // Если reCAPTCHA не пройдена, возвращаем ошибку
            if(!$responseKeys["success"] || $responseKeys["score"] < 0.5) {
                header('Content-Type: application/json');
                echo json_encode([
                    'result' => 'error',
                    'info' => 'Ошибка проверки reCAPTCHA',
                    'desc' => 'Возможная попытка спама'
                ]);
                exit;
            }
        } else {
            header('Content-Type: application/json');
            echo json_encode([
                'result' => 'error',
                'info' => 'Отсутствует токен reCAPTCHA'
            ]);
            exit;
        }
    
        // Переменные, которые отправляет пользователь
        $name = $_POST['name'] ?? '';
        $tel = $_POST['tel'] ?? '';
        $email = $_POST['email'] ?? '';
        $number = $_POST['number'] ?? '';
        $text = $_POST['text'] ?? '';
    
        // Формирование самого письма
        $title = "Заявка с сайта";
        $body = "
        <h2>Заявка с сайта</h2>
        <b>Имя:</b> $name<br>
        <b>Телефон:</b> $tel<br>
        <b>Почта:</b> $email<br>
        <b>Количество изделий:</b> $number<br>
        <b>Сообщение:</b><br>$text
        ";
    
        // Настройки PHPMailer
        $mail = new PHPMailer\PHPMailer\PHPMailer();
    
        try {
            $mail->isSMTP();
            $mail->CharSet = "UTF-8";
            $mail->SMTPAuth = true;
            //$mail->SMTPDebug = 2;
            $mail->Debugoutput = function($str, $level) use (&$data) {
                $data['debug'][] = $str;
            };
    
            // Настройки вашей почты
            $mail->Host = 'smtp.yandex.com'; // SMTP сервера вашей почты
            $mail->Username = '***'; // Логин на почте
            $mail->Password = '***'; // Пароль на почте
            $mail->SMTPSecure = 'ssl';
            $mail->Port = 465;
            $mail->setFrom('***', 'Заявка с сайта'); // Адрес самой почты и имя отправителя
    
            // Получатель письма
            $mail->addAddress('***');
    
            // Прикрипление файлов к письму
            if (!empty($_FILES['file']['name'][0])) {
                for ($i = 0; $i < count($_FILES['file']['tmp_name']); $i++) {
                    if ($_FILES['file']['error'][$i] === 0) {
                        $mail->addAttachment($_FILES['file']['tmp_name'][$i], $_FILES['file']['name'][$i]);
                    }
                }
            }
            
            // Отправка сообщения
            $mail->isHTML(true);
            $mail->Subject = $title;
            $mail->Body = $body;
    
            // Проверяем отправленность сообщения
            if ($mail->send()) {
                $data['result'] = "success";
                $data['info'] = "Сообщение успешно отправлено!";
            } else {
                $data['result'] = "error";
                $data['info'] = "Сообщение не было отправлено. Ошибка при отправке письма";
                $data['desc'] = "Причина ошибки: {$mail->ErrorInfo}";
            }
        } catch (Exception $e) {
            $data['result'] = "error";
            $data['info'] = "Ошибка при отправке письма";
            $data['desc'] = $e->getMessage();
        }
    } else {
        $data['result'] = "error";
        $data['info'] = "В коде присутствует ошибка";
        $data['desc'] = error_get_last();
    }
    
    // Отправка результата
    header('Content-Type: application/json');
    echo json_encode($data);
    ?>

    Основные изменения:
    Правильная обработка reCAPTCHA:

    Использовал cURL вместо file_get_contents для лучшей обработки ошибок

    Добавил проверку до обработки формы

    При ошибке reCAPTCHA скрипт завершается с ошибкой

    Улучшенная обработка ошибок:

    Добавил try-catch для обработки исключений PHPMailer

    Исправил обработку файлов (используйте $_FILES вместо $file)

    JSON ответ:

    Теперь скрипт возвращает один JSON ответ, а не несколько

    Все сообщения об ошибках стандартизированы

    Безопасность:

    Добавил проверку наличия токена reCAPTCHA

    Использовал оператор объединения ?? для переменных формы

    На стороне клиента (HTML/JS):
    Убедитесь, что вы правильно реализовали reCAPTCHA v3 на клиентской стороне. Вот пример:
    <script src="https://www.google.com/recaptcha/api.js?render=ВАШ_КЛЮЧ_САЙТА"></script>
    <script>
    document.querySelector('form').addEventListener('submit', function(e) {
        e.preventDefault();
        
        grecaptcha.ready(function() {
            grecaptcha.execute('ВАШ_КЛЮЧ_САЙТА', {action: 'submit'}).then(function(token) {
                // Добавляем token к данным формы
                let formData = new FormData(document.querySelector('form'));
                formData.append('token', token);
                
                // Отправка формы
                fetch('ваш_обработчик.php', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    if(data.result === 'success') {
                        alert('Сообщение отправлено!');
                    } else {
                        alert('Ошибка: ' + data.info);
                    }
                })
                .catch(error => console.error('Error:', error));
            });
        });
    });
    </script>

    Замените ВАШ_КЛЮЧ_САЙТА на ваш ключ reCAPTCHA (site key) и ваш_обработчик.php на путь к вашему PHP-скрипту.
    Ответ написан
    Комментировать