Walidacja formularzy w JavaScript i PHP.


1. Wstęp

W poprzedmim rozdziale opisaliśmy walidację formularzy za pomocą klasy JavaScript. Zaznaczyliśmy przy tym, że dane muszą być powtórnie sprawdzane przez kod niezależny od środowiska i użytkownika. Innymi słowy, muszą być walidowane po stronie serwera. W tym celu wykorzystuje się na przykład PHP, które ze względu na prostotę, ogólną dotępnośc i łatwość implementacji - jest najczęściej stosowanym rozwiązaniem w aplikacjach niskobudżetowych. Z pewnością zaletą PHP jest modułowość i niewielkie koszty wdrożenia, wadami niejednolitość, słaba systematyzacja, niska wydajność, proceduralna budowa modułów, brak cache'owania (każdorazowe inicjowanie zmiennych), brak obiektowości z prawdziwego zdarzenia, szczątkowa obsługa DOM i przestrzeni nazw. Wiele z tych problemów miało rozwiązać wprowadzenie wersji 6.0, jednak prace nad projektem zarzucono. Dlaczego zatem PHP - odpowiedź jest prosta - popularność.

Mając gotową klasę JavaScript, po drobnych modyfikacjach i korektach, możemy ją w dużej części przepisać do PHP. Możemy również wykorzystać te same wzorce dopasowania, ujmując je w cudzysłowy.

Listing 1. Wzorce dopasowania w JavaScript. Plik: wzorce.js

var WzorzecFirma = /^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9@!%&+-_*.,:\s\'\"\/]+$/;
var WzorzecUlica = /^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź]{3,100}$|^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź]+[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9\s\-\.\/]+[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9]{1,100}$/;
var WzorzecKod = /^[0-9]{2}-[0-9]{3}$/;
var WzorzecMiasto = /^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź]{3,100}$|^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź]+[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9\s\-]+[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9]{1,100}$/;
var WzorzecKontakt = /^[A-ZŚŹŻŁĆa-zęłćńóżąźś]+\s[A-ZŚŹŻŁĆa-zęłćńóżąźś]+$|^[A-ZŚŹŻŁĆa-zęłćńóżąźś]+\s[A-ZŚŹŻŁĆa-zęłćńóżąźś]+[\-\s]+[A-ZŚŹŻŁĆa-zęłćńóżąźś]+$/;
var WzorzecTel = /^[0-9]{9}$/;
var WzorzecNiepuste = /\S{3}/; // niepuste, przynajmniej 3 znaki
var WzorzecEmail = /^\s*[\w\-\+_]+(\.[\w\-\+_]+)*\@[\w\-\+_]+\.[\w\-\+_]+(\.[\w\-\+_]+)*\s*$/;

Listing 2. Wzorce dopasowania w PHP. Plik: wzorce.php

<?php
$WzorzecFirma = "/^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9@!%&+-_*.,:\s\'\"\/]+$/";
$WzorzecUlica = "/^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź]{3,100}$|^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź]+[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9\s\-\.\/]+[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9]{1,100}$/";
$WzorzecKod = "/^[0-9]{2}-[0-9]{3}$/";
$WzorzecMiasto = "/^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź]{3,100}$|^[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź]+[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9\s\-]+[A-Za-zĄĘĆŁŃÓŚŻŹąęćłńóśżź0-9]{1,100}$/";
$WzorzecKontakt = "/^[A-ZŚŹŻŁĆa-zęłćńóżąźś]+\s[A-ZŚŹŻŁĆa-zęłćńóżąźś]+$|^[A-ZŚŹŻŁĆa-zęłćńóżąźś]+\s[A-ZŚŹŻŁĆa-zęłćńóżąźś]+[\-\s]+[A-ZŚŹŻŁĆa-zęłćńóżąźś]+$/";
$WzorzecTel = "/^[0-9]{9}$/";
$WzorzecNiepuste = "/\S{3}/"; // niepuste, przynajmniej 3 znaki
$WzorzecEmail = "/^\s*[\w\-\+_]+(\.[\w\-\+_]+)*\@[\w\-\+_]+\.[\w\-\+_]+(\.[\w\-\+_]+)*\s*$/";
?>

Listing 3. Klasa walidująca w JavaScript. Plik: walidacja.js

// Script: Walidacja formularzy
// Author: Ireneusz Sekula, http://secom.pl, 2011-09-21
// Free to use and abuse under the MIT license.

// Klasa walidujaca
function K_Walidacja(F_Nazwa,PrzyciskID) {
    var Tablica_Licznik = 0; P_Status = 0;
    var Tablica_N = new Array(), Tablica_T = new Array(), Tablica_S = new Array();
    this.Przycisk = document.getElementById(PrzyciskID);

    this.M_Pole = function(P_Nazwa,P_Typ,P_Wzorzec) {
        Tablica_N[Tablica_Licznik] = P_Nazwa;
        Tablica_T[Tablica_Licznik] = P_Typ;
        Tablica_S[Tablica_Licznik] = P_Wzorzec;
        Tablica_Licznik++;
    };
    this.Przycisk.onclick = function() { 
        var Tablica_Dlugosc = Tablica_N.length;
        for (var i=0; i<Tablica_Dlugosc; i++) {	
            M_SprawdzPole(F_Nazwa,Tablica_N[i],Tablica_T[i],Tablica_S[i]);
        };
        if (P_Status == Tablica_Dlugosc) {
            M_Komunikat(F_Nazwa,"JS - Formularz wypełniony prawidłowo!");
            P_Status = 0;
            //return true; // zakomentuj jezeli chcesz submitowac formularz lub wstaw akcje lub return true; 
        }
        else { 
            M_Komunikat(F_Nazwa,"JS - Formularz wypełniony nieprawidłowo!");
            P_Status = 0;
            return false;
        };
    };
};
K_Walidacja.prototype.Prototyp = function() {
    M_SprawdzPole = function(F_Nazwa,P_Nazwa,P_Typ,P_Wzorzec) {    
        var P_Wartosc = document.forms[F_Nazwa][P_Nazwa].value;
        var P_Element = document.forms[F_Nazwa][P_Nazwa];
        // mozna usuwac spacje i myslniki z pobranych wartosci
        // if (P_Typ == "Tel" || P_Typ == "NIP") { P_Wartosc = P_Wartosc.replace(/[\s-]/g, ""); };

        if (P_Typ == "NIP" || P_Typ == "REGON9" || P_Typ == "PESEL") {
            if (M_SprawdzNumer(P_Wartosc,P_Typ)) {
                P_Element.className = "K_Walid_OK";
                P_Status++;
            }
            else {
                P_Element.className = "K_Walid_Bl";
                P_Status--;
            };
        }
        else if (P_Wzorzec.test(P_Wartosc)) { 
            P_Element.className = "K_Walid_OK";
            P_Status++;
        }
        else { 
            P_Element.className = "K_Walid_Bl";
            P_Status--;
        };
    };
    M_SprawdzNumer = function(P_Wartosc,P_Typ) {
        if (P_Typ == "NIP") {
            if (P_Wartosc == "1234567890") { return false; };
            var P_Dlugosc = 10; 
            var CyfraKontrolna = parseInt(P_Wartosc.charAt(9));
            var TablicaWag = [6, 5, 7, 2, 3, 4, 5, 6, 7];
            var Dzielnik = 11;
        };
        if (P_Typ == "REGON9") {
            var P_Dlugosc = 9; 
            var CyfraKontrolna = parseInt(P_Wartosc.charAt(8));
            var TablicaWag = [8, 9, 2, 3, 4, 5, 6, 7];
            var Dzielnik = 11;
        };
        if (P_Typ == "PESEL") {
            var P_Dlugosc = 11; 
            var CyfraKontrolna = parseInt(P_Wartosc.charAt(10));
            var TablicaWag = [9, 7, 3, 1, 9, 7, 3, 1, 9, 7];
            var Dzielnik = 10;
        };
        if (P_Wartosc.length != P_Dlugosc || parseInt(P_Wartosc, 10) <= 0) { return false; };
        var SumaKontrolna = 0;
        for (var i = 0; i<P_Dlugosc-1; i++) {
            SumaKontrolna += parseInt(P_Wartosc.charAt(i)) * TablicaWag[i];
        }                     
        var WynikKontrolnyModulo = SumaKontrolna % Dzielnik;
        var ResztaKontrolna = (WynikKontrolnyModulo == 10)?0:WynikKontrolnyModulo; // if (WynikKontrolnyModulo == 10) { ResztaKontrolna = 0} else { ResztaKontrolna = WynikKontrolnyModulo}
        if (ResztaKontrolna == CyfraKontrolna) { return true; }
        else { return false; };
    };
    M_Komunikat = function(F_Nazwa,K_Tekst) {
        var S_Komunikat = document.getElementById("K_"+F_Nazwa);
        if (S_Komunikat != null) { S_Komunikat.parentNode.removeChild(S_Komunikat); }
        var Komunikat=document.createElement("div");
        Komunikat.setAttribute("id", "K_"+F_Nazwa);
        //Komunikat.setAttribute("class", "K_Walid_Komunikat"); // nie dziala pod IE
        Komunikat.className = "K_Walid_Komunikat";
        var KomunikatTekst = document.createTextNode(K_Tekst);
        Komunikat.appendChild(KomunikatTekst);
        document.forms[F_Nazwa].appendChild(Komunikat);
    };
};

Listing 4. Klasa walidująca w PHP. Plik: walidacja.inc

<?php
// Script: Walidacja formularzy
// Author: Ireneusz Sekula, http://secom.pl, 2011-09-21
// Free to use and abuse under the MIT license.

class K_Walidacja {
    public $Tablica_Licznik = 0;
    public $P_Status = 0;
    public $Tablica_N = array();
    public $Tablica_T = array();
    public $Tablica_S = array();

    public function __construct($F_Nazwa,$Przycisk_Nazwa) {
        $this->F_Nazwa = $F_Nazwa;
        $this->Przycisk = $Przycisk_Nazwa;
    } 
    public function __destruct() {
    } 
    public function M_Pole($P_Nazwa,$P_Typ,$P_Wzorzec) {
        $this->Tablica_N[$this->Tablica_Licznik] = $P_Nazwa;
        $this->Tablica_T[$this->Tablica_Licznik] = $P_Typ;
        $this->Tablica_S[$this->Tablica_Licznik] = $P_Wzorzec;
        $this->Tablica_Licznik++; 
    }
    public function M_Przycisk() {
        if (isset($_POST[$this->Przycisk])) {
            for ($i=0; $i<$this->Tablica_Licznik; $i++) {	
                $this->M_SprawdzPole($this->Tablica_N[$i],$this->Tablica_T[$i],$this->Tablica_S[$i]);
            }
        }
        if ($this->P_Status == $this->Tablica_Licznik) {
            $this->M_Komunikat("PHP - Formularz wypełniony prawidłowo!");
            $this->P_Status = 0;
            return true;
        }
        else { 
            $this->M_Komunikat("PHP - Formularz wypełniony nieprawidłowo!");
            $this->P_Status = 0;
            return false;
        }
    }
    public function M_SprawdzPole($P_Nazwa,$P_Typ,$P_Wzorzec) {    
        $this->P_Nazwa = $P_Nazwa;
        $this->P_Wzorzec = $P_Wzorzec;
        $this->P_Typ = $P_Typ;
        $this->P_Wartosc = trim($_POST[$this->P_Nazwa]);

        if ($this->P_Typ == "NIP" || $this->P_Typ == "REGON9" || $this->P_Typ == "PESEL") {
            if ($this->M_SprawdzNumer()) { $this->P_Status++; }
            else { $this->P_Status--; }
        }
        else if (preg_match($this->P_Wzorzec, $this->P_Wartosc)) { $this->P_Status++; }
        else { $this->P_Status--; }
    }
    public function M_SprawdzNumer() {
        if ($this->P_Typ == "NIP") {
            if ($this->P_Wartosc == "1234567890") { return false; };
            $this->P_Dlugosc = 10; 
            $this->TablicaWag = array(6, 5, 7, 2, 3, 4, 5, 6, 7);
            $this->Dzielnik = 11;
        };
        if ($this->P_Typ == "REGON9") {
            $this->P_Dlugosc = 9; 
            $this->TablicaWag = array(8, 9, 2, 3, 4, 5, 6, 7);
            $this->Dzielnik = 11;
        };
        if ($this->P_Typ == "PESEL") {
            $this->P_Dlugosc = 11; 
            $this->TablicaWag = array(9, 7, 3, 1, 9, 7, 3, 1, 9, 7);
            $this->Dzielnik = 10;
        };
        if (strlen($this->P_Wartosc) != $this->P_Dlugosc || intval($this->P_Wartosc, 10) <= 0) { return false; };
        $this->CyfraKontrolna = intval(substr($this->P_Wartosc, -1));
        $this->SumaKontrolna = 0;
        for ($i = 0; $i<$this->P_Dlugosc-1; $i++) {
            $this->SumaKontrolna += intval($this->P_Wartosc[$i]) * $this->TablicaWag[$i];
        }                     
        $this->WynikKontrolnyModulo = $this->SumaKontrolna % $this->Dzielnik;
        $this->ResztaKontrolna = ($this->WynikKontrolnyModulo == 10)?0:$this->WynikKontrolnyModulo; 
        if ($this->ResztaKontrolna == $this->CyfraKontrolna) { return true; }
        else { return false; };
    }
    public function M_Komunikat($K_Tekst) {
        $this->K_Tekst = $K_Tekst;
        echo '<div class="K_Walid_Komunikat">'.$this->K_Tekst.'</div>';;
    }
    public function M_Wartosc($P_Nazwa) {
        if (!isset($_POST[$P_Nazwa])) { $_POST[$P_Nazwa] = ""; }
        echo $_POST[$P_Nazwa];
    }
}
?>

Jak widać klasa PHP ma algorytm podobny do klasy JavaScript, której działanie szczegółowo opisaliśmy w rodziale 1.10 Walidacja formularzy - JS (stąd odstępujemy od opisywania kodu PHP). Ponieważ PHP nie obsługuje dynamicznie istniejącej struktury DOM (zob. Klasa DOMDocument, Podręcznik DOM), nie ma możliwości stylowania elementów (pól formularza) przy ich prawidłowej lub błędnej walidacji. Problemem tym zajmiemy się później

Formularze i obiekty tworzymy w osobnym pliku. Wywołanie metody M_Wartość(Nazwa_Pola) pozwala kontrolować nam atrybut value każdego pola i nadawać mu wartość jego zmiennej $_POST, dzięki czemu po przeładowaniu strony - pola zawierają ostatnią wpisaną zawartość.

Listing 5. Kod HTML odpowiedzialny za utworzenie fomularza. Kod PHP i JavaScipt opdowiedzialny za utworzenie obiektu.

 <!DOCTYPE html>
<html>
<head>
<style type="text/css">
.K_Walid_Komunikat { /*display:none;*/ }
</style>
</head>
<body>
<?php
include "walidacja.inc";
$O_Walidacja0 = new K_Walidacja("F_Waliduj0","F_Przycisk0");
$O_Walidacja0->M_Pole("P_Kontakt0","Kontakt",$WzorzecKontakt);
$O_Walidacja0->M_Pole("P_Tel0","Tel",$WzorzecTel);
$O_Walidacja0->M_Pole("P_Email0","Email",$WzorzecEmail);
$O_Walidacja0->M_Pole("P_Tekst0","Tekst",$WzorzecNiepuste);
?>
<form name="F_Waliduj0" method="post">
Imię i nazwisko: <input type="text" name="P_Kontakt0" value="<?php $O_Walidacja0->M_Wartosc("P_Kontakt0"); ?>" /><br />
Telefon: <input type="text" name="P_Tel0" value="<?php $O_Walidacja0->M_Wartosc("P_Tel0"); ?>" /><br />
E-mail: <input type="text" name="P_Email0" value="<?php $O_Walidacja0->M_Wartosc("P_Email0"); ?>" /><br />
Uwagi: <textarea name="P_Tekst0"><?php $O_Walidacja0->M_Wartosc("P_Tekst0"); ?></textarea><br />
<input type="submit" id="F_Przycisk0" name="F_Przycisk0" value="Sprawdź" />
</form>
<?php $O_Walidacja0->M_Przycisk(); ?>
</body>
</html>

Przykład. Walidacja formularza na podstawie Listingów 4, 5.

Imię i nazwisko:
Telefon:
E-mail:
Uwagi:

PHP - Formularz wypełniony nieprawidłowo!

Przykład. Walidacja dwóch formularzy na podstawie Listingów 3, 4, 5.

Nazwa firmy:
Ulica:
Kod pocztowy:
Miejscowość:
NIP:
REGON9:
PESEL:
Imię i nazwisko:
Telefon:
E-mail:
Uwagi:

Imię i nazwisko:
Telefon:
E-mail:
Uwagi:

Zobacz demo: Walidacja formularzy

Ireneusz Sekuła, JavaScript dla zielonych