Formularz z wykorzystaniem Lightbox, PHP i Ajax. Część 2 – back-end

form-title-part2.jpg

W pierwszej części tego artykułu pokazałem jak stworzyć prosty formularz w HTML i wyświetlić go w lightbox. W drugiej części zajmiemy się walidacją i zapisywaniem danych pochodzących z formularza. Naszym podstawowym celem jest stworzenie bazy danych, w której będziemy przechowywać dodane wartości, zabezpieczyć się przed niechcianymi wartościami w polach formularza oraz bezpieczny zapis danych w PHP. Oto charakterystyczne cechy, jakie chcemy uzyskać od naszego formularza:

  • proste działanie
  • użyteczna walidacja danych
  • bezpieczeństwo pod kątem SQL Injection i XSS
  • maksymalne wykorzystanie możliwości, jakie daje nam jQuery i AJAX

Zobacz demo.

Baza danych

Tworzymy bardzo prostą bazę danych zawierającą identyczne pola jak nasz formularz, plus dodatkowa kolumna id z kluczem głównym. Tabele taką, możemy stworzyć ręcznie w dostarczanych przy bazie narzędziach np. phpMyAdmin, lub po prostu wykonać w php podane niżej zapytanie.

CREATE TABLE `links` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`title` VARCHAR( 255 ) NOT NULL ,
`url` VARCHAR( 255 ) NOT NULL ,
`desc` TEXT NOT NULL
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci;

Kod JavaScript

Potrzebna nam jest funkcja, która po naciśnięciu przycisku „Dodaj”, wyśle zapytanie do serwera, w którym nasze dane zostaną sprawdzone i jeżeli wszystko będzie w porządku, dodane do bazy danych. W przeciwnym wypadku wyświetlimy błędy, które należy poprawić przed ponownym zatwierdzeniem formularza. Realizacje tych zadań rozpoczniemy od prostej obsługi kliknięć w nasz przycisk na końcu formularza:

$("button#save").click(function(){
return false;
});

Zwrócenie wartości false, powoduje zatrzymania domyślnego wykonania działania przycisku. W naszym przypadku zatrzymuje automatyczne wysłanie zapytania metodą POST, przez przeglądarkę. Opcja ta nie jest przez nas pożądana, ponieważ chcemy sami wykonać żądanie za pomocą metody $.ajax dostępnej w jQuery. W tym momencie można się zastanawiać, dlaczego nie zrezygnować z type=”submit”? Chodzi o to, iż planując tego typu formularze, dobrym zwyczajem jest pomyśleć o osobach, które nie mają włączonej obsługi JavaScript w swojej przeglądarce, dla nich cały nasz poniższy kod JavaScript zostanie zignorowany. Dlatego powinniśmy, przynajmniej w podstawowy sposób, umożliwić skorzystanie z formularza. Jak łatwo się domyślić w naszym przypadku brak JS nie wpłynie w żaden sposób na działanie formularza, ponieważ zwyczajnie go nie zobaczymy w związku z wykorzystaniem Colorbox. Pomimo to, w artykule częściowo uwzględniona zostanie opcja wyłączonej obsługi JavaScript.

Kolejne linijki to nic ciekawego, zwykłe usuwanie ewentualnych błędów, które pojawiły się nam za pierwszym wykonaniem formularza:

//kasujemy poprzednie bledy w formularzu
$('div.error-list').remove();
$('form *').removeClass('error');
// zmienna z ewentualnymi bledami
var errorlist = '';

Jednak dalej przechodzimy do najważniejszej części naszego kodu, czyli wykorzystanie metody $.ajax dostępnej w jQuery:

$.ajax({
type: "POST",
dataType:"json",
data: $('form').serialize()+'&ajax=1',
success: function(msg){
//kod wykonywany po zwroceniu wartosci od skryptu php
}
});

Nie będę szczegółowo omawiam wszystkich możliwości, jakie daje nam ta funkcja, zainteresowanych odsyłam do obszernego manuala, w którym znajdziemy również kilka dobrych przykładów jej stosowania. My ustawiliśmy POST jako typ żądania, oraz „json” jako format spodziewanej odpowiedzi od serwera. Parametr data zawiera dane, jakie chcemy przesłać do naszego pliku php. W tym przypadku wykorzystaliśmy funkcje serialize, która zwróci nam dane z wypełnionego formularza. Do danych formularza dołączyliśmy także zmienną ajax z wartością 1, co pozwoli nam potem sprawdzić w skrypcie PHP czy żądanie jest wykonane przy pomocy AJAX. Dalej widzimy zdarzenie success, które wykona się w przypadku pozytywnie zakończonego żądania do serwera. Parametr funkcji – msg, zawiera wiadomość zwrotną od naszego skryptu. Zawartość tej funkcji znajduje się na poniższym listingu:

success: function(msg){
if (msg.ok == 1)
{
//czynnosci wykonywane przy pomyslnym zapisie do bazy
alert('Dane zostały zapisane');
//zamyka colorbox
$.colorbox.close();
}
else
{
//wyswietlanie bledow
}
return false;
}

Kod sprowadza się do prostego warunku, jeżeli zmienna msg.ok równa się 1, to znaczy, że dodanie do bazy danych z naszego formularza powiodło się i możemy wykonać jakąś czynność, w naszym przypadku wyświetlamy informację, że dane zostały zapisane, ale równie dobrze może to być np uaktualnienie listy już wyświetlanych linków lub coś podobnego. Należy pamiętać o zamknięciu naszego colorbox, w przeciwnym wypadku formularz będzie cały czas wyświetlany. Z drugiej strony, jeżeli msg.ok nie istnieje lub nie równa się 1 to znaczy, że w formularzu wystąpił błąd. Za jego wyświetlanie odpowiada poniższy kod:

$.each(msg, function(index, value) {
if (index =='all')
$('form input,form textarea').addClass('error');
else
$('#'+index).addClass('error');

errorlist += '<li>'+value+'</li>';
});

// wyswietlanie bledu
$("h2").after("<div class=\"error-list\"><p><strong>
Wystapily bledy:</strong></p><ul>" +errorlist+"</ul></div>");
// odswierzenie wymiarow colorboxa
$.colorbox.resize();

W pętli each dodajemy klasę error do kolejny pól formularza, co podświetli nam na czerwono błędnie wypełnione pola, dzięki czemu użytkownik będzie widział wartości, których pól wypełnił niepoprawnie. Oprócz tego w zmiennej errorlist dopisujemy kolejne informacje, o przyczynie błędu, dzięki czemu nasz użytkownik będzie wiedział, jaki błąd został wykryty przez skrypt. Kolejna linijka tworzy naszą informacje o błędach na górze formularza, zaraz po tagu h2. Ponieważ dodanie kolejnego kodu HTML do zawartość colorbox, wpłynie na jego rozmiar dobrze jest odświeżyć wymiary naszego okna poprzez metodę resize() tak, aby uniknąć pojawienia się nie potrzebnie pionowego scrolla.

Tym sposobem nasz cały nasz JavaScript wygląda tak:

$("button#save").click(function(){
//kasujemy poprzednie bledy w formularzu
$('div.error-list').remove();
$('form *').removeClass('error');
// zmienna z ewentualnymi bledami
var errorlist = '';
//wysylamy zapytanie typu POST
$.ajax({
type: "POST",
dataType:"json",
data: $('form').serialize()+'&ajax=1',
success: function(msg){
//alert(msg.ok);
if (msg.ok == 1)
{
//czynnosci wykonywane przy pomyslnym zapisie do bazy
alert('Dane zostały zapisane');
//zamyka colorbox
$.colorbox.close();
}
else
{
//wyswietlanie bledow
$.each(msg, function(index, value) {
if (index =='all')
$('form input,form textarea').addClass('error');
else
$('#'+index).addClass('error');

errorlist += '<li>'+value+'</li>';
});
$("h2").after("<div class=\"error-list\"><p>
<strong>Wystapily bledy:</strong></p><ul>" +errorlist+"</ul></div>");
$.colorbox.resize();
}
return false;
}
});
return false;
});

Kod PHP

OK, jeżeli przebrnęliśmy przez JavaScript, to teraz mamy już z górki. Zostało nam napisanie kodu PHP. A właściwie faktyczną walidację danych, oraz dodanie informacji z formularza do utworzonej wcześniej bazy danych.

Podstawową sprawą jest miejsce umieszczenia kodu PHP. Jak można zauważyć w naszym kodzie nie ustawiliśmy żadnego adresu w parametrze action formularza, podobnie jak w metodzie $.ajax pominęliśmy parametr url, innymi słowy formularz zostanie wysłany do tego samego pliku php, w którym mamy nasz kod HTML i JavaScript. W związku z tym cały poniższy kod zamieścimy na początku naszego pliku.

Zaczniemy od prostego sprawdzenia czy wysłaliśmy coś przez nasz formularz, czego przejawem będzie zmienna $_POST, która nie będzie miała pustej wartości:

if (!empty($_POST)) {

//dane naszej bazy danych
$hostname = 'localhost';
$username = 'root';
$password = 'pass';
$dbname = 'example_db';
$errorMsg = '';

$title = $_POST['title'];
$url = $_POST['url'];
$desc = $_POST['desc'];
}

Wewnątrz naszego warunku znajduje się kilka zmiennych, które zawierają dane potrzebne do połączenia z naszą bazą danych. Zerujemy wartość zmiennej przechowującej informacje o naszych błędach, a następnie przypisujemy zmienne do ich odpowiedników w tablicy $_POST. Nie jest to konieczne, ale dla mnie kod staje się wtedy czytelniejszy.

Dobrze! Posiadamy już wszystkie dane, teraz należy sprawdzić czy są one poprawne, oraz czy nie zawierają nie bezpiecznych dla nas znaków lub kodów. Z pomocą przychodzi nam bardzo przydatna funkcja PHP filter_var. Zachęcam do dokładniejszego zapoznania się z jej dokumentacją, a w szczególności z jej opcjami. My wykorzystamy tylko dwie:

  • FILTER_SANITIZE_STRING – która sprawdzi czy nasza zmienna zawiera tylko bezpieczne znaki i wyczyści kod dodany przez złośliwych użytkowników.
  • FILTER_VALIDATE_URL – opcja ta sprawdzi czy nasz adres url jest prawidłowy

Sprawdzenie trzech naszych zmiennych zajmuje się poniższy kod:

if (!empty($title)) {
$title = filter_var($title, FILTER_SANITIZE_STRING);
if (empty($title)) {
$errorMsg['title']= 'Tytuł zawiera niedozwolone znaki';
}
} else {
$errorMsg['title']= 'Musisz podać tytuł';
}

if (!empty($url)) {
if (filter_var($url, FILTER_VALIDATE_URL) == FALSE) {
$errorMsg['url'] = 'Podany link jest nie prawidlowy';
}
} else {
$errorMsg['url']= 'Musisz podać adres url';
}

if (!empty($desc)) {
$desc = filter_var($desc, FILTER_SANITIZE_STRING);
if (empty($desc)) {
$errorMsg['desc'] = 'Opis zawiera niedozwolone znaki';
}
} else {
$errorMsg['desc'] = 'Musisz napisać krótką informacje';
}

Jeżeli wystąpiły jakieś błędy ich treść zostanie zapisana w zmiennej $errorMsg. Kluczem będzie nazwa przekazana przez $_POST, która pozwala nam zaznaczyć odpowiednie pole formularza zawierające błąd.

if (empty($errorMsg)) {
//...
//dodawanie danych do bazy
//...

if ($_POST['ajax']==1)
{
echo json_encode(array('ok'=>1));
die();
}
else
{
//tu kod w przypadku braku JavaScript
}
} else {
if ($_POST['ajax']==1)
{
echo json_encode($errorMsg);
die;
}
else
{
//tu kod w przypadku braku JavaScript
}
}

Powyższy kod sprawdza czy wykryto jakiekolwiek błędy. Jeżeli tak, to wysyłamy informacje o nich do naszego formularza. Jeżeli zapytanie było poprzez AJAX (zmienna $_POST[‘ajax’] będzie miała wartość 1), wysyłamy tablicę błędów w formacie JSON. Dla Was pozostawiam napisanie kodu w przypadku, gdy JavaScript jest wyłączoną. Jeżeli będziecie mieć z tym jakieś problemy, napiszcie w komentarzach, a z przyjemnością doradzę i pomogę.

PDO – czyli dodajemy dane do bazy

Ostatnim, ale również kluczowym etapem naszej pracy jest dodanie danych z formularza do bazy, z której potem te dane będziemy mogli w dowolny sposób pobierać. Wykorzystamy do tego PDO. Dlaczego? Ponieważ jest to nowoczesne i bezpieczne rozwiązanie. Całość naszego kodu sprowadza się do zaledwie paru linijek:

try {
$dbh = new PDO('mysql:host=' . $hostname . ';dbname=' . $dbname, $username, $password);
$q = $dbh->prepare("INSERT INTO links (title,url,desc) VALUES (:title,:author,:desc)");
$q->execute(array(':title' => $title,
':link' => $url,
':desc' => $desc));
} catch (PDOException $e) {
echo $e->getMessage();
die;
}

Łączymy się z PDO wykorzystując dane w zmiennych na początku skryptu, następnie wykonujemy zapytanie INSERT, które dodaje nam nasze informacje do bazy danych. Jeżeli wystąpi błąd w zapytaniu uruchomiony zostanie wyjątek, który wyświetli nam treść błędu. Wykorzystanie w tym przykładzie metody prepare() powszechnie uznawane jest za najlepsze, a zdecydowanie najprostsze, zabezpieczenie przed SQL Injection. Jeżeli zapytanie nie wywołało żadnego błędu wysyłamy w postaci JSON tablice o kluczu „ok” i wartości 1. Podobnie jak w przypadku walidacji zachęcam do indywidualnego dokończenia kodu w przypadku braku JavaScript. Zobaczmy jak wygląda nasz kod PHP w całości:

 

if (!empty($_POST)) {

//dane naszej bazy danych
$hostname = 'localhost';
$username = 'root';
$password = 'pass';
$dbname = 'example_db';
$errorMsg = '';

$title = $_POST['title'];
$url = $_POST['url'];
$desc = $_POST['desc'];

// walidacja danych
if (!empty($title)) {
$title = filter_var($title, FILTER_SANITIZE_STRING);
if (empty($title)) {
$errorMsg['title'] = 'Tytuł zawiera niedozwolone znaki';
}
} else {
$errorMsg['title'] = 'Musisz podać tytuł';
}

if (!empty($url)) {
if (filter_var($url, FILTER_VALIDATE_URL) == FALSE) {
$errorMsg['url'] = 'Podany link jest nie prawidlowy';
}
} else {
$errorMsg['url'] = 'Musisz podać adres url';
}

if (!empty($desc)) {
$desc = filter_var($desc, FILTER_SANITIZE_STRING);
if (empty($desc)) {
$errorMsg['desc'] = 'Opis zawiera niedozwolone znaki';
}
} else {
$errorMsg['desc'] = 'Musisz napisać krótką informacje';
}

if (empty($errorMsg)) {
try {
$dbh = new PDO('mysql:host=' . $hostname . ';dbname=' . $dbname, $username, $password);
$q = $dbh->prepare("INSERT INTO links (title,url,desc) VALUES (:title,:author,:desc)");
$q->execute(array(':title' => $title,
':link' => $url,
':desc' => $desc));
} catch (PDOException $e) {
echo $e->getMessage();
die;
}

if ($_POST['ajax'] == 1) {
echo json_encode(array('ok' => 1));
die();
} else {
//tu kod w przypadku braku JavaScript
}
} else {
if ($_POST['ajax'] == 1) {
echo json_encode($errorMsg);
die;
} else {
//tu kod w przypadku braku JavaScript
}
}
}

 

Formularz jest gotowy! W tym miejscu możemy zobaczyć prezentacje efektów naszej pracy. Identyczny system jest zastosowany przy dodawaniu linków społeczności na stronie głównej Webnote.

Podsumowanie

Tym sposobem zakończyliśmy dwu częściowy artykuł, o tym jak zbudować prosty formularz. Wykorzystaliśmy do tego celu popularne obecnie techniki, jak lightbox i jQuery, a nasz kod jest stosunkowo bezpieczny i odporny na podstawowe ataki. Artykuł ten może też być podstawą do budowy własnych rozwiązań na stronach internetowych. Przy jego pomocy możemy zbudować formularz do szybkiego kontaktu z administracją, dodawanie sugestii do strony, szybkie logowanie itp. Podstawy tych rozwiązań są zawsze takie same i wyglądają mniej więcej tak jak w tym artykule. Miłego kodowania.

DyskusjaKomentarze: 4

  • Leszek 23 maj 2012 15:14
    Hej,
    Niezły artykuł. Wykorzystanie filtrów i PDO!

    Pytania:
    1. Dlaczego zamiast: SERVER['REQUEST_METHOD'] == 'POST zastosowałeś: !empty($_POST)?
    2. Dlaczego dataType: 'json' zamisat dataType: 'html'?
    3. Brakuje mi tu generowanego w php tokena w formularzu
  • Leszek 23 maj 2012 15:34
    A i jeszcze jedno, skoro nie ma obsługi bez JS, to dlaczego walidacją danych formularza nie zajmuje się JS? A PHP to sprawdza i ew. odrzuca dane.

    2. - nieaktualne pytanie.
  • Krzysztof Bachula
    Autor artykułu
    31 maj 2012 17:49
    @Leszek fajnie, że artykuł Ci się podoba. Co do pytań:
    1. W zasadzie to nie ma to znaczenia, w obu przypadkach osiągniesz ten sam efekt. Osobiście i tak działam zawsze w Frameworkach, więc tego typu sprawdzanie działa na zasadzie:

    $this->request->isPOST == true

    albo coś podobnego. Na potrzeby artykułu tego typu warunek uznałem za wystarczający.
    3. Tu się zgadzam, można dodać jeszcze token dla większego bezpieczeństwa.

    W domyśle w tym artykule jest w sparcie dla braku włączonego JS. Może inaczej, wszystko co jest potrzebne do obsługi wyłączonego JavaScript znajduje się w artykule, wystarczy dopisać tylko przypadki ich obsługi. Np. najprostsza metoda zapisania błedów w sesji, odświeżenie formularza i wyświetlenie błedów.

    Osobiście jestem zwolennikiem sprawdzania błędów po stronie serwera, nawet jeżeli na początku obsługujemy walidację tylko przez JS. W przypadku konieczności dodania obsługi bez włączonego JS, znacznie skrócimy czas naszej pracy i nie będziemy dublować kodu.
  • Piotr 29 sierpień 2012 09:40
    Witam, mam problem gdy wpiszę tylko jedno w to pokazuje mi błąd "null" dam zły link to "Błąd zły link" a gdzie wszystko ok to nic się nie dzieje wie ktoś dla czego?

Dodaj komentarz Komentarze są moderowane, a przy linkach używane jest rel="nofollow". Prosimy o nie reklamowanie i nie spamowanie w komentarzach.
Linki tworzone za pomocą tagu [url] np: [url=www.xyz.pl]xyz[/url]
Źródła za pomoc tagu [code] z wskazaniem języka np. [code=php] echo [/code]

Copyright © 2022 Webnote

Projekt i wykonanie: Tworzenie stron internetowych

Dodaj link