Перейти к публикации

Форма обратной связи c загрузкой файла. AJAX + PHP + JS + Google Recaptcha v2


Рекомендованные сообщения

Screenshot-2019-09-17-Offline.png

 

Отправка письма без перезагрузки страницы.

Пока не пройдена проверка Recapcha кнопка отправки заблокирована.

 

Для стилизации используется Bootstrap 4, в целом стилизация на ваше усмотрение.

Ключи для Recapcha получаете тут https://www.google.com/recaptcha/admin/create, нужна версия v2.

 

Использован код с сайтов:

  1. https://proverstka.com.ua/blog/skript-formy-obratnoj-svyazi-s-prikrepleniem-fajla-php-ajax/
  2. https://xdan.ru/proverka-recaptcha-2-0-s-pomoshchyu-php-i-javascript.html
  3. https://codeby.net/blogs/forma-obratnoj-svjazi-s-ispolzovaniem-ajax-otpravkoj-soobshhenija-po-pochte-i-vozmozhnostju-prikrepit-fajl/

 

В секцию HEAD добавить:

<script type="text/javascript" src="https://www.google.com/recaptcha/api.js?onload=reCaptchaShow&render=explicit&hl=ru"></script>

 

В подвал добавить (первый скрипт для кастомизации поля выбора файла):

<script src="https://cdn.jsdelivr.net/npm/bs-custom-file-input/dist/bs-custom-file-input.min.js" type="text/javascript"></script>
<script src="{THEME}/js/sendrequest.js"></script>

 

Форма:

    <div class="bg_form">
        <div class="container">
            <div class="row row_bottom_form">
                <div class="col-xl-4">
                    <div class="big_head">Заголовок</div>
                    <div class="desc">Описание</div>
                </div>
                <div class="col-xl-8">
                    <div class="bg_form2">
                        <form method="post" action="/engine/ajax/sendrequest.php" id="sendform" enctype="multipart/form-data">
                            <div class="form-group">
                                <input name="name" value="" type="text" class="form-control form-control-lg" placeholder="Имя*" pattern=".{3,20}" required title="Укажите ваше Имя" />
                            </div>
                            <div class="form-group">
                                <input name="org" value="" type="text" class="form-control form-control-lg" placeholder="Организация*" pattern=".{3,50}" required title="Укажите вашу организацию" />
                            </div>
                            <div class="form-group">
                                <input name="phone" value="" type="tel" class="form-control form-control-lg" placeholder="Телефон*" pattern=".{10,20}" required title="Укажите ваш телефон" />
                            </div>
                            <div class="form-group">
                                <input name="adress" value="" type="text" class="form-control form-control-lg" placeholder="Адрес объекта*" pattern=".{3,50}" required title="Укажите адрес объекта" />
                            </div>
                            <div class="custom-control custom-checkbox form-control-lg custom-control-inline">
                                <input type="checkbox" name="assembling" class="custom-control-input" id="id_assembling" value="0">
                                <label class="custom-control-label" for="id_assembling">Монтаж</label>
                            </div>
                            <div class="custom-control custom-checkbox form-control-lg custom-control-inline">
                                <input type="checkbox" name="cover" class="custom-control-input" id="id_cover" value="0" />
                                <label class="custom-control-label" for="id_cover">Резиновое покрытие</label>
                            </div>
                            <div class="custom-file form-control-lg custom-control-inline">
                                <input type="file" class="custom-file-input" name="file" id="id_file" required />
                                <label class="custom-file-label" for="id_file" data-browse="Выбрать файл">Прикрепить ведомость МАФ*</label>
                            </div>
                            <div class="form-group">
                                <textarea name="message" class="form-control form-control-lg" rows="4" placeholder="Сообщение" /></textarea>
                            </div>
                            <div class="row mt-4">
                                <div class="col-xl-7">
                                    <div id="recaptcha" class="g-recaptcha"></div>
                                </div>
                                <div class="col-xl-5">
                                    <input value="Отправить" class="btn btn-success btn-lg btn-block" id="btn_send" type="submit" disabled />
                                </div>
                            </div>
                            
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

 

Файл sendrequest.js, положить в папку js вашего шаблона:

window.onload = function () { 
  if(!window.FormData) {
    alert("Браузер не поддерживает загрузку файлов на этом сайте");
  }
}

$(document).ready(function(){
    bsCustomFileInput.init();
    var errorTxt = 'Ошибка отправки';

    $("#sendform").submit(function(form) {
        form.preventDefault();
        $( ".bg_form .btn.btn-success" ).prop( "disabled", true );
        $( ".bg_form .btn.btn-success" ).val("Отправка сообщения...");
        var form = document.forms.sendform,
        formData = new FormData(form),
        xhr = new XMLHttpRequest();
        xhr.open("POST", "/engine/ajax/sendrequest.php");
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                if(xhr.status == 200) {
                    $("div.bg_form .col-xl-8").html('<div class="send_message">Ваше сообщение отправлено.<br /> Мы свяжемся с вами в ближайшее время.</div>');
                }
            }
        };
        xhr.send(formData);
    }); 
})

$('#id_assembling').change(function() {$(this).val($(this).prop('checked')?'1':'0');});
$('#id_cover').change(function() {$(this).val($(this).prop('checked')?'1':'0');});

function reCaptchaShow() {
  try {
    grecaptcha.reset();
  } catch (e) {}

  grecaptcha.render('recaptcha', {
    sitekey: 'КЛЮЧ_САЙТА_Recaptcha',
    callback: function() {
      $('#btn_send').prop('disabled', false);
    }
  });
}

 

PHP обработчик sendrequest.php, положить в папку engine/ajax:

<?php
    $to = 'почта_от_кого';
    $email = 'почта_кому';

    $response = $_POST["g-recaptcha-response"];
    $url = 'https://www.google.com/recaptcha/api/siteverify';
    $data = [
        'secret' => 'СЕКРЕТНЫЙ_КЛЮЧ_Recapcha',
        'response' => $_POST["g-recaptcha-response"]
    ];
    $options = [
        'http' => [
            'method' => 'POST',
            'content' => http_build_query($data)
        ]
    ];
    $context  = stream_context_create($options);
    $verify = file_get_contents($url, false, $context);
    $captcha_success=json_decode($verify);
    
    if ($captcha_success->success==true) {
        $name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $org = filter_input(INPUT_POST, 'org', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $phone = filter_input(INPUT_POST, 'phone', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $adress = filter_input(INPUT_POST, 'adress', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $assembling = filter_input(INPUT_POST, 'assembling', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $cover = filter_input(INPUT_POST, 'cover', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $message = filter_input(INPUT_POST, 'message', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);

        if ( !empty( $_FILES['file']['tmp_name'] ) and $_FILES['file']['error'] == 0 ) {
            $filepath = $_FILES['file']['tmp_name'];
            $filename = $_FILES['file']['name'];
        } else {
            $filepath = '';
            $filename = '';
        }

        $body = "Имя: ".$name."\r\n";
        $body .= "Организация: ".$org."\r\n";
        $body .= "Телефон: ".$phone."\r\n";
        $body .= "Адрес: ".$adress."\r\n";
        if($assembling == '1') { $body .= "Монтаж: Требуется\r\n"; }
        if($cover == '1') { $body .= "Резиновое покрытие: Требуется\r\n"; }
        if(strlen($message) > 1) { $body .= "\r\nСообщение: ".$message; }

        send_mail($to, $body, $email, $filepath, $filename);
    }


    // Вспомогательная функция для отправки почтового сообщения с вложением
    function send_mail($to, $body, $email, $filepath, $filename) {
        $subject = 'Форма заказа с сайта';
        $boundary = "--".md5(uniqid(time())); // генерируем разделитель
        $headers = "From: ".$email."\r\n";   
        $headers .= "MIME-Version: 1.0\r\n";
        $headers .="Content-Type: multipart/mixed; boundary=\"".$boundary."\"\r\n";
        $multipart = "--".$boundary."\r\n";
        $multipart .= "Content-type: text/plain; charset=\"utf-8\"\r\n";
        $multipart .= "Content-Transfer-Encoding: quoted-printable\r\n\r\n";

        $body = $body."\r\n\r\n";

        $multipart .= $body;

        $file = '';
        if ( !empty( $filepath ) ) {
            $fp = fopen($filepath, "r");
            if ( $fp ) {
                $content = fread($fp, filesize($filepath));
                fclose($fp);
                $file .= "--".$boundary."\r\n";
                $file .= "Content-Type: application/octet-stream\r\n";
                $file .= "Content-Transfer-Encoding: base64\r\n";
                $file .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
                $file .= chunk_split(base64_encode($content))."\r\n";
            }
        }
        $multipart .= $file."--".$boundary."--\r\n";
        mail($to, $subject, $multipart, $headers);
    }
?>

 

При желании можно интуитивно допилить форму под ваши нужды.

Если кто то "допилит" отправку средствами DLE то буду благодарен.

Изменено пользователем Medik
Ссылка на сообщение
Поделиться на других сайтах
1 час назад, Medik сказал:

 

Если кто то "допилит" отправку средствами DLE то буду благодарен.

Да, требует доработки. Вечером сделаю.

Ссылка на сообщение
Поделиться на других сайтах
<?php

if(!defined('DATALIFEENGINE')) {
	header( "HTTP/1.1 403 Forbidden" );
	header ( 'Location: ../../' );
	die( "Hacking attempt!" );
}

    $response = $_POST["g-recaptcha-response"];
    $url = 'https://www.google.com/recaptcha/api/siteverify';
    $data = [
        'secret' => 'СЕКРЕТНЫЙ_КЛЮЧ_Recapcha',
        'response' => $_POST["g-recaptcha-response"]
    ];
    $options = [
        'http' => [
            'method' => 'POST',
            'content' => http_build_query($data)
        ]
    ];
    $context  = stream_context_create($options);
    $verify = file_get_contents($url, false, $context);
    $captcha_success=json_decode($verify);
    
    if ($captcha_success->success==true) {
		
		include_once (DLEPlugins::Check(ENGINE_DIR . '/classes/mail.class.php'));
		$mail = new dle_mail( $config, $is_html = true );
		
        $name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $org = filter_input(INPUT_POST, 'org', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $phone = filter_input(INPUT_POST, 'phone', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $adress = filter_input(INPUT_POST, 'adress', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $assembling = filter_input(INPUT_POST, 'assembling', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $cover = filter_input(INPUT_POST, 'cover', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $message = filter_input(INPUT_POST, 'message', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);

        $body = "Имя: {$name}<br>";
        $body .= "Организация: {$org}<br>";
        $body .= "Телефон: {$phone}<br>";
        $body .= "Адрес: {$adress}<br>";
        if($assembling == '1') { $body .= "Монтаж: Требуется<br>"; }
        if($cover == '1') { $body .= "Резиновое покрытие: Требуется<br>"; }
        if(strlen($message) > 1) { $body .= "<br>Сообщение: {$message}"; }
		if(!empty( $_FILES['file']['tmp_name'] ) and $_FILES['file']['error'] == 0 ) {
			$mail->addAttachment($_FILES['file']['tmp_name']);
        }
        
		// Настройки отправки используются из настроек DLE
		// EMAIL КОМУ - поменять на адрес получателя
		$mail->send("EMAIL КОМУ", "Форма заказа с сайта", $body);

    }


?>

 

Не проверял, но должно работать, если у вас работало.

Желательно сделать более лучшую проверку файлов (чтобы не загрузили вредоносный исполняемый файл).

 

В ajax запросе адрес поменяйте на /engine/ajax/controller.php?mod=sendrequest

 

И можно переходить на рекапчу 3 версии.

Изменено пользователем webair
Ссылка на сообщение
Поделиться на других сайтах
18.09.2019 в 02:02, webair сказал:

$mail->addAttachment($_FILES['file']['tmp_name']);

Пришлось поменять на

$mail->addAttachment($_FILES['file']['tmp_name'], $_FILES['file']['name']);

иначе файл имел имя типа "php8J5D9d" без расширения.

 

В целом работает, благодарю за доработку.

Ссылка на сообщение
Поделиться на других сайтах

PHP обработчик sendrequest.php, положить в папку engine/ajax:

Отправка через DLE, на почту админа.

<?php

if( !defined('DATALIFEENGINE') ) {
    header( "HTTP/1.1 403 Forbidden" );
    header ( 'Location: ../../' );
    die( "Hacking attempt!" );
}

    $response = $_POST["g-recaptcha-response"];
    $url = 'https://www.google.com/recaptcha/api/siteverify';
    $data = [
        'secret' => 'СЕКРЕТНЫЙ_КЛЮЧ_Recapcha',
        'response' => $_POST["g-recaptcha-response"]
    ];
    $options = [
        'http' => [
            'method' => 'POST',
            'content' => http_build_query($data)
        ]
    ];
    $context  = stream_context_create($options);
    $verify = file_get_contents($url, false, $context);
    $captcha_success=json_decode($verify);
    
    if ($captcha_success->success==true) {
        
        include_once (DLEPlugins::Check(ENGINE_DIR . '/classes/mail.class.php'));
        include ENGINE_DIR . '/data/config.php';

        $mail = new dle_mail( $config, $is_html = true );
        
        $name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $org = filter_input(INPUT_POST, 'org', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $phone = filter_input(INPUT_POST, 'phone', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $adress = filter_input(INPUT_POST, 'adress', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $assembling = filter_input(INPUT_POST, 'assembling', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $cover = filter_input(INPUT_POST, 'cover', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
        $message = filter_input(INPUT_POST, 'message', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);

        $body = "Имя: {$name}<br>";
        $body .= "Организация: {$org}<br>";
        $body .= "Телефон: {$phone}<br>";
        $body .= "Адрес: {$adress}<br>";
        if($assembling == '1') { $body .= "Монтаж: Требуется<br>"; }
        if($cover == '1') { $body .= "Резиновое покрытие: Требуется<br>"; }
        if(strlen($message) > 1) { $body .= "<br>Сообщение: {$message}"; }
        if(!empty( $_FILES['file']['tmp_name'] ) and $_FILES['file']['error'] == 0 ) {
            $mail->addAttachment($_FILES['file']['tmp_name'], $_FILES['file']['name']);
        }
        
        $mail->send($config['admin_mail'], "Форма заказа с сайта", $body);

    }

?>

 

Ссылка на сообщение
Поделиться на других сайтах
  • 6 месяцев спустя...

Присоединяйтесь к обсуждению

Вы можете опубликовать сообщение сейчас, а зарегистрироваться позже. Если у вас есть аккаунт, войдите в него для написания от своего имени.

Гость
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Вставить в виде обычного текста

  Разрешено не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

×
×
  • Создать...