Jump to content
Sign in to follow this  
Medik

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

Recommended Posts

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 то буду благодарен.

Edited by Medik

Share this post


Link to post
Share on other sites
1 час назад, Medik сказал:

 

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

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

  • Upvote 1

Share this post


Link to post
Share on other sites
<?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 версии.

Edited by webair
  • Thanks 1

Share this post


Link to post
Share on other sites
18.09.2019 в 02:02, webair сказал:

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

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

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

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

 

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

Share this post


Link to post
Share on other sites

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);

    }

?>

 

Share this post


Link to post
Share on other sites

Еще "галочку" надо для согласия с обработкой персональных данных. Без этого такие формы вне закона.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...