Formularz kontaktowy

Poniższy tekst będzie w zasadzie podsumowaniem tego, co sobie powiedzieliśmy w poprzednich rozdziałach. Naszym celem będzie stworzenie w pełni działającego dynamicznego formularza kontaktowego.

HTML i CSS

Zaczynamy od prostego kodu HTML i CSS, który przewijał nam się już w poprzednich dyskusjach:

Pokaż HTML

<form class="form" id="contactForm" method="post" action="./send-script.php">
    <div class="form-row">
        <label for="name">Imię (min. 3 znaki)*</label>
        <input type="text" name="name" required pattern=.{3,} id="name" data-error-text="Wypełnij to pole">
    </div>
    <div class="form-row">
        <label for="email">Email*</label>
        <input type="email" name="email" required id="email" data-error-text="Wpisz poprawny email">
    </div>
    <div class="form-row">
        <label for="message">Wiadomość*</label>
        <textarea name="message" required data-error-text="Musisz wypełnić pole" id="message"></textarea>
    </div>
    <div class="form-row">
        <button type="submit" class="submit-btn">
            Wyślij
        </button>
    </div>
</form>

Pokaż CSS

* {
    box-sizing: border-box;
}

.form {
    margin: 3rem auto;
    font-family: sans-serif;
    max-width: 40rem;
}

.form .form-row {
    margin-bottom: 1rem;
}

.form .form-row:last-child {
    margin-bottom: 0;
}

.form input,
.form textarea {
    font-family: sans-serif;
    padding: 0.8rem;
    border: 1px solid #bbb;
    display: block;
    width: 100%;
    color: #666;
}

.form textarea {
    height: 10rem;
}

.form label {
    display: block;
    font-size: 0.9rem;
    margin-bottom: 0.5rem;
}

.form .submit-btn {
    font-family: sans-serif;
    padding: 1rem 2rem;
    cursor: pointer;
    background: tomato;
    border: 0;
    border-radius: 0.2rem;
    color: #FFF;
    font-size: 1.1rem;
    font-weight: bold;
    transition: 0.3s background-color;
}

@media screen and (max-width: 500px) {
    .form .submit-btn {
        display: block;
        width: 100%;
    }
}

/* ---------------------------------------------------- */
/* walidacja formularza JS */
/* ---------------------------------------------------- */
.form input.field-error,
.form textarea.field-error {
    border-color: tomato;
    outline: none;
    box-shadow: 0 0 0 2px rgba(255,99,71, 0.3);
}
.form-error-text {
    color: tomato;
    font-size: 0.8rem;
    margin-top: 5px;
}
.form-error-inline .form-error-text {
    display: none;
}


/* ---------------------------------------------------- */
/* sukces i błąd wysyłania */
/* ---------------------------------------------------- */
.form-send-error {
    font-family: sans-serif;
    color: red;
    margin: 10px 0;
}

.form-send-success {
    font-family: sans-serif;
    color: red;
    margin: 10px 0;
}

.form-send-success {
    color: inherit;
}

.form-send-success strong {
    display: block;
    font-size: 1.5em;
    color: tomato;
    margin-bottom: 0.3em;
}

Wygląd formularza możesz zobaczyć tutaj.

Do naszego formularza wybierzemy sposób z umieszczeniem komunikatów błędów w dataset pól. Tak jak to robiliśmy w tamtym rozdziale - każde wymagane pole w naszym formularzu będzie miało dodatkowy atrybut data-error-text, który zawiera tekst wyświetlany w razie błędu. W razie jeżeli nie wiesz o czym mówimy, zapraszam do lektury.

Początkowy skrypt

Żeby na siłę nie powtarzać czynności, zacznijmy od punktu, na którym skończyliśmy w poprzednim rozdziale, to jest na podpięciu sprawdzania pól w czasie pisania, ale i przy próbie wysyłki formularza:


const form = document.querySelector("#contactForm");
const inputs = form.querySelectorAll("[required]");

//wyłączam validationApi by nie przeszkadzało
form.setAttribute("novalidate", true);

//dodaję dynamiczną walidację pól
for (const el of inputs) {
    el.addEventListener("input", e => markFieldAsError(e.target, !e.target.checkValidity()));
}

function toggleErrorField(field, show) {
    const errorText = field.nextElementSibling;
    if (errorText !== null) {
        if (errorText.classList.contains("form-error-text")) {
            errorText.style.display = show ? "block" : "none";
            errorText.setAttribute('aria-hidden', show);
        }
    }
}

function markFieldAsError(field, show) {
    if (show) {
        field.classList.add("field-error");
    } else {
        field.classList.remove("field-error");
        toggleErrorField(field, false);
    }
}

Samą wysyłkę napiszemy jako oddzielną funkcję:


function checkElements() {
    let formErrors = false;

    for (const el of inputs) {
        markFieldAsError(el, false);
        toggleErrorField(el, false);

        if (!el.checkValidity()) {
            markFieldAsError(el, true);
            toggleErrorField(el, true);
            formErrors = true;
        }
    }

    return formErrors;
}

function submitForm(e) {
    let formErrors = checkElements();

    if (!formErrors) {
        //form.submit();
        //dane będziemy wysyłać dynamicznie!
    }
}

form.addEventListener("submit", e => {
    e.preventDefault();
    submitForm()
});

Sprawdź formularz w akcji

Wysyłka formularza

Żeby wysłać dane, musimy pobrać wszystkie dane z formularza. Wystarczy do tego użyć formData:


...

function checkElements() {
    ...
}

function submitForm() {
    let formErrors = checkElements();

    if (!formErrors) {
        const formData = new FormData(form);
    }
}

Przed samym wysłaniem danych wyłączmy przycisk submit poprzez dodanie do niego atrybutu disabled. Dzięki temu zniecierpliwiony użytkownik nie będzie mógł klikać w przycisk wysyłania aż do czasu zakończenia poprzedniej wysyłki.

Dodatkowo powinniśmy pokazać jakiś wskaźnik wczytywania. Możemy to zrobić za pomocą prostej animacji:


.loading {
    position: relative;
    pointer-events: none;
    opacity:0.5;
}

.loading::after {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 2px solid rgba(0, 0, 0, 0.2);
    border-right-color: rgba(0,0,0,0.7);
    transform: translate(-50%, -50%) rotate(0deg);
    content:"";
    animation: rotateSingleLoading 0.3s infinite linear;
    z-index: 10;
}

@keyframes rotateSingleLoading {
    0% {
        transform: translate(-50%, -50%) rotate(0deg);
    }
    100% {
        transform: translate(-50%, -50%) rotate(360deg);
    }
}

const loadingTest = document.querySelector("#loadingTest")
loadingTest.addEventListener("click", e => {
    loadingTest.classList.add("loading");
    loadingTest.disabled = true;
});

Do samej wysyłki zastosujemy fetch. Napiszmy do tego oddzielną funkcję, która zwróci nam odpowiednie dane:


const form = document.querySelector("#contactForm");
const url = "https://skrypt-na-serwerze.php";

...

function makeRequest(data) {
    return fetch(url, {
        method : "post"
        body: data
    })
    .then(res => {
        if (res.ok) {
            return res.json()
        } else {
            return Promise.reject(`${res.status}: ${res.statusText}`);
        }
    });
}

function submitForm() {
    let formErrors = checkElements();

    if (!formErrors) {
        const formData = new FormData(form);

        const submit = form.querySelector("[type=submit]");
        submit.disabled = true;
        submit.classList.add("loading");

        makeRequest(formData)
            .then(res => {
                //tutaj odpowiedź
            })
            .catch(err => {
                //tutaj błędy
            })
            .finally(() => { //gdy zakończy się połączenie chcemy włączyć przycisk submit
                submit.disabled = false;
                submit.classList.remove("loading");
            });
    }
}

Po stronie serwera

Formularz wysłaliśmy na serwer. Do naszych celów użyjemy PHP, ale podobne działanie można utworzyć w każdej innej technologii serwerowej:


<?php

$mailToSend = "twoj-mail@lorem.pl";

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $name = $_POST["name"];
    $email = $_POST["email"];
    $message = $_POST["message"];

    $errors = [];
	$return = [];

    if (empty($name)) { //jeżeli pusta wartość
        array_push($errors, "name");
    }
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { //sprawdzamy czy email ma zły wzór
        array_push($errors, "email");
    }
    if (empty($message)) {
        array_push($errors, "message");
    }

    if (count($errors) > 0) {
        $return["errors"] = $errors;
    } else {
        //każde wysłanie wiadomości musi być poprzedzone ustawieniem nagłówków
        $headers  = "MIME-Version: 1.0" . "\r\n";
        $headers .= "Content-type: text/html; charset=UTF-8". "\r\n";
        $headers .= "From: ".$email."\r\n";
        $headers .= "Reply-to: ".$email;
        $message  = "
            <html>
                <head>
                    <meta charset=\"utf-8\">
                </head>
                <body>
                    <div> Imię: $name</div>
                    <div> Email: <a href=\"mailto:$email\">$email</a> </div>
                    <div> Wiadomość: </div>
                    <div> $message </div>
                </body>
            </html>";

        if (mail($mailToSend, "Wiadomość ze strony - " . date("d-m-Y"), $message, $headers)) {
            $return["status"] = "success";
        } else {
            $return["status"] = "error";
        }
    }

    header("Content-Type: application/json");
    echo json_encode($return);
}

Jest to prosty skrypt, który kolejno sprawdza przesłane pola. Jeżeli dane są poprawne, skrypt spróbuje wysłać maila.

Zwrócone do Javascript dane mogą być w 3 postaciach:

  • {status: "success"} - gdy wszystko poszło dobrze i wiadomość została wysłana
  • {status: "error"} - dane z formularza były poprawne, ale z jakiegoś powodu nie udało się wysłać wiadomości
  • {"errors" : ["name", "email", "message"] } - tablica zawierająca nazwy pól, które zostały wysłane z formularza z błędnymi danymi

Czasami mogą się pojawić problemy z wysyłką maila z naszego serwera. Może to być spowodowane wieloma czynnikami. Niektóre serwery wymagają by nagłówek From wskazywał na maila, który mamy podpięty pod dany serwer. Inne wymagają dodatkowych parametrów.
A i nie zawsze będziemy korzystać przecież z PHP. Może w naszym przypadku lepiej sprawdzi się nodemailer? A nawet czasami nie potrzeba w ogóle skryptów na serwerze. Zawsze możemy skorzystać z usług darmowych dostawców statycznych formularzy, które to serwisy wyślą takie maile za nas. Dobre zestawienie znajdziesz pod adresem https://css-tricks.com/a-comparison-of-static-form-providers/

Tutaj znajdziesz też wersję dla Node.js. Korzysta ona z express, oraz z NodeMailera.

Do sprawdzenia maila użyłem paczki email-validator. Dane wysyłamy w przy użyciu FormData, dlatego musimy też użyć dodatkowej paczki express-form-data.

Aby użyć poniższego skryptu powinieneś zainstalować odpowiednie paczki. Oczywiście przydał by się też plik package.json. Mówiliśmy o tym tutaj.


    npm i express body-parser nodemailer cors email-validator express-form-data
    

Poniższy skrypt ustawiony jest dla konta Gmail. Nodemailer pozwala też skorzystać z innych serwerów. Można o tym poczytać na ich stronie.

Dane będziemy wysyłać na adres http://localhost:3002/sendMail.


    //ogólny opis nodemailera:
    //https://nodemailer.com/about/

    //dla konta które będzie wysyłać maile za pomocą google trzeba dodatkowo włączyć:
    //https://myaccount.google.com/lesssecureapps
    const account = {
        user : '...twoj-login-na-gmail',
        pass : '...twoj-password-na-gmail'
    }

    const express = require('express');
    const path = require('path');
    const bodyParser = require('body-parser');
    const formData = require('express-form-data');
    const cors = require('cors');
    const app = express();

    const nodemailer = require('nodemailer');
    const emailValidator = require('email-validator');


    // odpalamy parsowanie requestow dla express
    app.use( bodyParser.json() );
    app.use(cors())
    app.use(formData.parse());
    app.use(bodyParser.urlencoded({ extended: true }));


    //żeby nie mieć problemów z corsami strona index.html i serwer musza byc na tej samej domenie
    //wiec ja serwujemy z tego serwera
    app.get('/', function (req, res) {
        res.sendFile(path.resolve(__dirname + '/index.html'))
    });

    //nasłuchujemy żądania danego typu (get, post, put, path, delete)
    app.post('/sendMail', (req, res) => {
        //obiekt który bede zwracał
        let returnObj = {}
        console.log(req.body)
        //ustawiam nagłówek dla zwrotki
        res.setHeader('Content-Type', 'application/json');

        //sprawdzam prymitywnie dane które przyszły z formularza
        if (!emailValidator.validate(req.body.email)) {
            if (!returnObj.errors) returnObj.errors = [];
            returnObj.errors.push("email");
        }

        if (req.body.name === undefined || req.body.name === "") {
            if (!returnObj.errors) returnObj.errors = [];
            returnObj.errors.push("name");
        }

        if (req.body.message === undefined || req.body.message === "") {
            if (!returnObj.errors) returnObj.errors = [];
            returnObj.errors.push("message");
        }

        //jeżeli są błędy
        if (returnObj.errors) {
            res.setHeader('Content-Type', 'application/json');
            res.send(JSON.stringify(returnObj));
        } else {
            let transporter = nodemailer.createTransport({
                service : 'gmail',
                host: 'smtp.gmail.com',
                port: 587,
                secure: false,
                requireTLS: true,
                auth: {
                    user: account.user,
                    pass: account.pass
                }
            });

            let mailOptions = {
                from: account.user,
                to: account.user,
                subject: 'Wiadomość ze strony',
                text: `
                    Imię: ${req.body.name}
                    Email: ${req.body.email}
                    Wiadomość:
                    ${req.body.message}
                `,
                html: `
                    <html>
                        <head>
                            <meta charset="utf-8">
                        </head>
                        <body>
                            <div> Imię: ${req.body.name} </div>
                            <div> Email: <a href="mailto:${req.body.email}">${req.body.email}</a> </div>
                            <div> Wiadomość: </div>
                            <div> ${req.body.message} </div>
                        </body>
                    </html>`
            };

            transporter.sendMail(mailOptions, (error, info) => {
                if (error) {
                    console.log('Email sent ERROR: ' + error);
                    returnObj.status = "error";
                } else {
                    console.log('Email sent SUCCESS: ' + info.response);
                    returnObj.status = "success";
                }
                res.send(JSON.stringify(returnObj));
            });
        }

    });


    /* statyczne pliki jak css, js, obrazki */
    app.get(/^(.+)$/, (req, res) => {
        res.sendFile(path.resolve(__dirname + '/' + req.params[0]));
    });


    //odpalamy...
    const port = 3002;
    app.listen(port, () => {
        console.log(`Listening on http://localhost:${port}`);
    });

    

Odpowiedź z serwera

Serwer dostał dane, obsłużył je i zwraca nam odpowiedź w 3 wariantach.

Gdy w odpowiedzi dostaniemy zmienną errors, zakładamy, że będzie to tablica z nazwami błędnie wypełnionych pól. Każdą wartość tej tablicy (linie 17-18) zmieniamy za pomocą map na tablicę selektorów CSS np. [name="email"], [name="message"]. Następnie taką tablicę łączymy za pomocą join(","), dzięki czemu uzyskujemy zapis:


const selectors = res.errors.map(el => `[name="${el}"]`);
const fieldsWithErrors = form.querySelectorAll(ret.errors.join(","));

//powyższe jest równoznaczne z
const fieldsWithErrors = form.querySelectorAll(`[name="name"],[name="email"],[name="message"]...`)

Zastosujmy powyższą logikę w naszej funkcji i odpalmy ją w funkcji wysyłającej formularz:


function makeRequest(data) {
    return fetch(url, {
        method,
        body: data
    })
    .then(res => {
        if (res.ok) {
            return res.json()
        } else {
            return Promise.reject(`${res.status}: ${res.statusText}`);
        }
    });
}

function afterSubmit(res) {
    if (res.errors) { //błędne pola
        const selectors = res.errors.map(el => `[name="${el}"]`);
        const fieldsWithErrors = form.querySelectorAll(selectors.join(","));
        for (const el of fieldsWithErrors) {
            markFieldAsError(el, true);
            toggleErrorField(el, true);
        }
    } else { //pola są ok - sprawdzamy status wysyłki
        if (res.status === "success") {
            //wyświetlamy komunikat powodzenia
        }
        if (res.status === "error") {
            //komunikat błędu np gdy nie dało się wysłać wiadomości
        }
    }
}

function submitForm() {
    let formErrors = checkElements();

    if (!formErrors) {
        const formData = new FormData(form);

        const submit = form.querySelector("[type=submit]");
        submit.disabled = true;
        submit.classList.add("loading");

        makeRequest(formData)
            .then(res => {
                afterSubmit(res);
            })
            .catch(err => {
                //tutaj błędy
            })
            .finally(() => {
                submit.disabled = false;
                submit.classList.remove("loading");
            });
    }
}

Odpowiedź z serwera, błąd serwera

Pozostały nam do obsługi odpowiedzi, gdy status równy jest "success" i "error".

Dla "error", możemy dodać do formularza tekst z ogólnym komunikatem o błędzie:


function showSubmitError(text) {
    //jeżeli istnieje komunikat o błędzie wysyłki
    //np. generowany przy poprzednim wysyłaniu formularza
    //usuwamy go, by nie duplikować tych komunikatów
    const statusError = document.querySelector(".send-error");
    if (statusError) statusError.remove();

    const div = document.createElement("div");
    div.classList.add("send-error");
    div.innerText = "Wysłanie wiadomości się nie powiodło";
    submit.parentElement.appendChild(div);
}

function afterSubmit(res) {
    if (res.errors) { //błędne pola
        const selectors = res.errors.map(el => `[name="${el}"]`);
        const fieldsWithErrors = form.querySelectorAll(selectors.join(","));
        for (const el of fieldsWithErrors) {
            markFieldAsError(el, true);
            toggleErrorField(el, true);
        }
    } else { //pola są ok - sprawdzamy status wysyłki
        if (res.status === "success") {
            //wyświetlamy komunikat powodzenia, cieszymy sie
        }
        if (res.status === "error") {
            showSubmitError(res.status);
        }
    }
}

Tą samą funkcję możemy dodatkowo użyć, by wyświetlić błędy dla samego fetch (np. gdy występuje brak połączenia, albo adres wysyłki jest błędny):


function submitForm() {
    let formErrors = checkElements();

    if (!formErrors) {
        const formData = new FormData(form);

        const submit = form.querySelector("[type=submit]");
        submit.disabled = true;
        submit.classList.add("loading");

        makeRequest(formData)
            .then(res => {
                afterSubmit(res);
            })
            .catch(err => {
                showSubmitError(err);
            })
            .finally(() => {
                submit.disabled = false;
                submit.classList.remove("loading");
            });
    }
}

Odpowiedź z serwera, wreszcie pozytywnie

Zajmijmy się teraz pozytywną odpowiedzią. Możemy tutaj oczywiście wstawiać dynamicznie tekst tak samo, jak powyżej w przypadku błędów. Ja zazwyczaj jednak po pozytywnej wysyłce zastępuję cały formularz nową zawartością. Dzięki temu będzie on trochę bardziej odporny na różne ataki robotów lub ludzi, którzy lubią wysyłać formularze za pomocą np. setInterval:


function showSubmitSuccess() {
    const div = document.createElement("div");
    div.classList.add("form-send-success");
    form.parentElement.insertBefore(div, form);
    div.innerHTML = `
        <strong>Wiadomość została wysłana</strong>
        <span>Dziękujemy za kontakt. Postaramy się odpowiedzieć jak najszybciej</span>
    `;
    form.remove();
}

function afterSubmit(res) {
    if (res.errors) {
        const selectors = res.errors.map(el => `[name="${el}"]`);
        const fieldsWithErrors = form.querySelectorAll(selectors.join(","));
        for (const el of fieldsWithErrors) {
            markFieldAsError(el, true);
            toggleErrorField(el, true);
        }
    } else {
        if (res.status === "success") {
            showSubmitSuccess();
        }
        if (res.status === "error") {
            showSubmitError(res.status);
        }
    }
}

Prosty antyspam

Powyżej stworzyliśmy prosty w pełni dynamiczny formularz kontaktowy. Problem z takimi formularzami jest taki, że bardzo lubią je roboty rozsyłające spam. Aby im przeszkodzić, musimy jakoś zabezpieczyć nasze dzieło. Jedną ze łatwiejszych metod jest tak zwany honeypot. Metoda ta polega na dodaniu do formularza dodatkowego pola, które ukrywamy za pomocą styli:


<span class="form-row honey-row">
    <label for="honey">Jeżeli jesteś człowiekiem, nie wypełniaj tego pola</label>
    <input type="text" name="honey">
</span>

.form .honey-row {
    display:none;
}

Większość robotów ignoruje style, ani nie rozumie języka pisanego, więc wypełnią to pole. Wystarczy teraz po stronie serwera sprawdzić, czy pole to ma wartość. Jak ma, olewamy całą sprawę, ewentualnie pokrzepiając robota miłymi słowami wiadomości w formie sukcesu:


<?php
$mailToSend = "twoj-email@lorem.pl";

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $name = $_POST["name"];
    $email = $_POST["email"];
    $message = $_POST["email"];
    $antiSpam = $_POST["honey"];

    $errors = Array();
	$return = Array();

    if (empty($antiSpam)) {

        //tutaj cała reszta skryptu który mieliśmy wcześniej (od 23 do 49)
        if (count($errors) > 0) {
            $return["errors"] = $errors;
        } else {
            ...
        }

    } else {
        $return["status"] = "success";
    }

    header("Content-Type: application/json");
    echo json_encode($return);
}

Recaptcha

Powyższy sposób nie jest idealny i bardzo łatwo można go obejść. Głupi robot może i wypełni powyższe pole, ale użytkownik nie musi. Wystarczy, że raz wyśle formularz i sprawdzi jak wygląda takie zapytanie.

Mimo wszystko w realnych projektach warto skorzystać z Recaptchy. Wersja 3 jest niewidoczna dla użytkownika (nie trzeba klikać jakiś dziwnych obrazków), a i jest bardzo łatwa do zaimplementowania.

Po pierwsze musimy wejść na stronę https://developers.google.com/recaptcha. Następnie na górze strony wchodzimy w Recaptcha v3 admin console. Po wejściu w link musimy podać etykietę (nazwa porządkowa), wybrać wersję recaptchy (v3) oraz domenę (adres) naszej strony. Po przejściu dalej dostaniemy 2 klucze. Jeden do użycia w kodzie html/js strony, a drugi do użycia po stronie serwera (np. w kodzie php).

Wystarczy potem postępować zgodnie z punktami z tej odpowiedzi.

Przykładowa implementacja tego rozwiązania w naszym kodzie może mieć postać:


function submitForm() {
    let formErrors = checkElements();

    if (!formErrors) {
        //tutaj wysyłka
        const formData = new FormData(form);

        const submit = form.querySelector("[type=submit]");
        submit.disabled = true;
        submit.classList.add("loading");


        grecaptcha.ready(() => {
            grecaptcha.execute(recaptchaKey, {action: 'submit'}).then(token => {
                formData.append("token", token);

                makeRequest(formData).then(res => {
                    afterSubmit(res);
                })
                .catch(err => {
                    showSubmitError(err);
                })
                .finally(() => {
                    inputSubmit.disabled = false;
                    inputSubmit.classList.remove("loading");
                });
            });
        });
    }
}

form.addEventListener("submit", submit);

Po stronie serwera:


<?php
$mailToSend = "twoj-email@lorem.pl";
//klucz pobierzesz ze strony gdzie zakładałeś recaptche
$secretRecaptchaKey = '...';

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $name = $_POST["name"];
    $email = $_POST["email"];
    $message = $_POST["email"];
    $antiSpam = $_POST["honey"];

    $errors = Array();
	$return = Array();

    if (!isset($_POST['token'])) die;
    $token = $_POST['token'];

    $response = file_get_contents(
        "https://www.google.com/recaptcha/api/siteverify?secret=$secretRecaptchaKey&response=$token&remoteip=".$_SERVER['REMOTE_ADDR']
    );
    $response = json_decode($response);

    if ($response->success === false) {
        header("Content-Type: application/json");
        die('{"status": "error"}'); //lub {"status" : "success"} dla zmylenia
    }

    //tutaj dalsza część skryptu który powyżej był w fragmencie "po stronie serwera"...
    $errors = [];
	$return = [];

    if (empty($name)) { //jeżeli pusta wartość
        array_push($errors, "name");
    }
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { //sprawdzamy czy email ma zły wzór
        array_push($errors, "email");
    }
    if (empty($message)) {
        array_push($errors, "message");
    }

    if (count($errors) > 0) {
        $return["errors"] = $errors;
    } else {
        //każde wysłanie wiadomości musi być poprzedzone ustawieniem nagłówków
        $headers  = "MIME-Version: 1.0" . "\r\n";
        $headers .= "Content-type: text/html; charset=UTF-8". "\r\n";
        $headers .= "From: ".$email."\r\n";
        $headers .= "Reply-to: ".$email;
        $message  = "
            <html>
                <head>
                    <meta charset=\"utf-8\">
                </head>
                <body>
                    <div> Imię: $name</div>
                    <div> Email: <a href=\"mailto:$email\">$email</a> </div>
                    <div> Wiadomość: </div>
                    <div> $message </div>
                </body>
            </html>";

        if (mail($mailToSend, "Wiadomość ze strony - " . date("d-m-Y"), $message, $headers)) {
            $return["status"] = "success";
        } else {
            $return["status"] = "error";
        }
    }

    header("Content-Type: application/json");
    echo json_encode($return);
}

Demo

Gotowy formularz znajdziesz poniżej:

demo

Wszelkie prawa zastrzeżone. Jeżeli chcesz używać jakiejś części tego kursu, skontaktuj się z autorem.
Aha - i ta strona korzysta z ciasteczek.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.