Zarejestrował się na Twojej stronie www. Imię, nazwisko, email, PESEL… gotowe. Formularz przyjął dane bez zająknięcia. Zaraz potem uzyskał dostęp do panelu, gdzie znalazł lukę pozwalającą na podejrzenie danych innych użytkowników. Zatarł ręce z radości na myśl o tym, ile na tych danych zarobi… Czy wspomniałem Ci już, że urodzi się dopiero za 68 lat i będzie kobietą? Dobra walidacja PESEL może Ci pomóc.

Walidacja PESEL – jak zacząć?

Wiele systemów pracuje na danych osobowych, a niektóre z nich poza imieniem, nazwiskiem i adresem email wymagają podania numeru PESEL. W sieci znajdziesz dość dużo bezpłatnych skryptów, które pozwalają zwalidować numer PESEL. Kryje się w nich kilka pułapek, które każdy deweloper stron powinien znać, aby móc ich uniknąć.

W tym wpisie proponuję Ci algorytm walidowania numeru PESEL i podpowiadam, jak możesz wykonać niezbędne operacje walidacyjne w języku PHP. Pamiętaj, że jest to tylko przykład, istotny jest nie tyle sam kod, co istota operacji merytorycznych. Można napisać kod, który wykona te same operacje na wiele sposobów, a Twojej uwadze polecam przede wszystkim merytorykę tych operacji, bo sam kod każdy może napisać w sposób, który odpowiada mu najbardziej pod kątem nazw zmiennych czy stosowanych instrukcji.

Proponuję na początku następujący schemat. Już w tym miejscu warto zwrócić uwagę, że większość algorytmów dostępnych w sieci kończy się na kroku trzecim, co niestety nie daje wiarygodnej walidacji PESEL – stąd kolejne kroki w tej propozycji.

Walidacja PESEL – typ danych i długość ciągu

Oczywiście prawidłowy PESEL zawsze składa się z 11 kolejnych cyfr dziesiętnych. Pierwszym krokiem analizy ciągu podanego jako PESEL powinno zatem być odrzucenie wszystkiego, co nie spełnia tego kryterium. Jednym ze sposobów realizacji tego kroku sprawdzania PESEL jest skorzystanie z funkcji preg_match. Dla zwalidowania zmiennej $pesel proponuję po prostu:

preg_match('/^[0-9]{11}$/', $pesel)

Walidacja PESEL – algorytm MSWiA

Algorytm PESEL zakłada 10 cyfr „merytorycznych” oraz ostatnią cyfrę kontrolną. Ma ona zapewnić odporność systemu na pomyłki przy podawaniu numeru PESEL.

Ograniczenia algorytmu

Algorytm stosowany przez MSWiA zapewnia pewien poziom odporności na błędnie podawane numeru PESEL, jednak nie jest to 100% pewności. Mamy do czynienia z zaledwie jedną cyfrą kontrolną, czyli 10 możliwościami. Istnieje kilka kombinacji poprzedzających cyfr, które mogą dać identyczną sumę kontrolną. W szczególności może to dotyczyć np. zamiany kolejności danych o dacie urodzenia, które podane w innej kolejności wciąż dadzą prawidłową sumę kontrolą, ale będzie to całkowicie inny numer PESEL!

Algorytm zakłada mnożenie każdej cyfry przez odpowiedni mnożnik, kolejno 1, 3, 7, 9, 1, 3, 7, 9, 1, 3. Tak otrzymany ciąg sumujemy i wyciągamy resztę z jego dzielenia przez 10, a następnie porównujemy z cyfrą kontrolną.

Tylko matematyczna poprawność

Ten rodzaj algorytmu pozwoli np. na odgadnięcie jednej brakującej cyfry w numerze PESEL. Inną jego cechą jest to, że zamiana dnia i roku w dacie da identyczną sumę kontrolą, co wynika z doboru wag w algorytmie.

Najważniejsze, żeby pamiętać, iż algorytm poprawności PESEL sprawdza tylko matematyczną poprawność, nie sprawdza danych merytorycznie

Tak walidacja PESEL pod kątem sumy kontrolnej może to wyglądać w kodzie PHP:


function isPeselCheckSumOk($pesel){
// Klasyczna walidacja wg algorytmu Luhna w implementacji PESEL
$arrWagi = array(1, 3, 7, 9, 1, 3, 7, 9, 1, 3); // tablica z odpowiednimi wagami
$intSum = 0;
for ($i = 0; $i < 10; $i++) {
$intSum += $arrWagi[$i] * $pesel[$i]; //mnożymy każdy ze znaków dla 10 pierwszych cyfr przez wagę i sumujemy wszystko
}
$int = 10 - $intSum % 10; //obliczamy sumę kontrolną i porównujemy ją z ostatnią cyfrą.
$intControlNr = ($int == 10)?0:$int; //sprawdzamy czy taka sama suma kontrolna jest w ciągu
if ($intControlNr == $pesel[10]){
   return true;
}
return false;
}

Co ciekawe, PESEL o wartości 00000000000 będzie tym algorytmem zwalidowany poprawnie!

Co więcej – poprawne będą także PESEL’e osób, które jeszcze się nie urodziły, a także takie, gdzie data urodzenia jest bezsensowna, np. wskazująca na 30. lutego. Błyskawicznie można wygenerować PESEL walidowany poprawnie, który sugeruje urodzenia w dniu nieistniejącym w kalendarzu.

Walidacja PESEL – data

W ten sposób dochodzimy do zagadnienia daty w numerze PESEL. Jest to obszar bardzo często błędnie rozumiany, głównie przez osoby urodzone w latach 1900-1999. Data urodzenia jest zakodowana w pierwszych 6 cyfrach numeru PESEL.

Pierwsze dwie oznaczają kolejny rok danego stulecia, piąta i szósta liczba to numer dnia w miesiącu, jak łatwo się domyślisz, trzecia i czwarta muszą zatem oznaczać miesiąc… i oznaczają. Właśnie dla osób urodzonych w latach 1900-1999. Takie osoby mają proste, intuicyjne numery PESEL, gdzie występuje rok (dwie ostatnie cyfry), miesiąc i dzień. Ponieważ rok jest kodowany tylko jako dwie cyfry, to istnieje domniemanie, że należy dodać do nich 1900, aby uzyskać faktyczny, pełny rok urodzenia. Osoba, której PESEL zaczyna się od 860615 urodziła się zatem 15. czerwca 1986 roku. Tak to działa dla ubiegłego stulecia i większość osób o tym wie.

Jeśli masz dziecko, albo sam jesteś bardzo młodą osobą, urodzoną po roku 1999, to wiesz jednak doskonale, że trzecia i czwarta cyfra to wcale nie jest po prostu miesiąc urodzenia. Dla osób urodzonych w innych stuleciach dodaje się stałą liczbę do liczby porządkowej miesiąca. Walidacja PESEL zakłada następujące wartości:

  • +20 dla osób urodzonych w latach 2000-2099,
  • +40 dla osób urodzonych w latach 2100-2199,
  • +60 dla osób urodzonych w latach 2200-2299,
  • +80 dla osób urodzonych w latach 1800-1899!

Zwróć uwagę na dość nieoczekiwaną sytuację osoby, urodzonej w XIX wieku, która przecież w latach 70’tych XX wieku mogła żyć i mieć nadany numer PESEL. Przykładowo dla numeru PESEL zaczynającego się od: 938310… interpretuje się, że jest to 10. marca 1893 roku.

Oto, jak walidacja PESEL co do poprawności daty może wyglądać w kodzie PHP:

  1. Tworzymy tablicę z liczbami 80, 0, 20,40,60, czyli liczbami dodawanymi do miesiąca urodzenia dla kolejnych stuleci.
  2. Tworzymy „normalną” tablicę od 1 do 12.
  3. Wywołując pętlę w pętli tworzymy tablicę zawierającą sumę każdej z tych liczb „dodatkowych” z „normalnym” numerem miesiąca.
  4. Uzyskana tablica zawiera wszystkie dopuszczalne oznaczenia miesięcy ma potrzeby walidacji PESEL.
  5. Sprawdzamy, czy podane oznaczenie miesięcy, zawiera się w ogóle w takiej tablicy. Odrzucamy w razie, jeśli tak się nie dzieje.
  6. Wyciągamy informację na temat stulecia i dodajemy ją do liczby złożonej z dwóch pierwszych cyfr PESEL, aby uzyskać klasyczny, czterocyfrowy rok.
function isPeselDateOkByMonth($pesel){
// Wyciągamy dzień i miesiąc
$miesiac=substr($pesel,2,2);
$dzien = substr($pesel,4,2);

// Budujemy tablicę miesięcy dozwolonych
$arrDodatkoweMiesiace = Array(80,0,20,40,60);
$arrMiesiaceBazowe = range(1,12);
foreach ($arrDodatkoweMiesiace as $miesiacDodatkowy){   foreach ($arrMiesiaceBazowe as $miesiacBazowy){       $arrMiesiace[]=$miesiacDodatkowy+$miesiacBazowy;    }
}

// Odrzucamy nieprawidłowo podane miesiące
if (!in_array($miesiac,$arrMiesiace)) return 'Nieprawidłowa data.';

// Ustalamy stulecie
if (substr($miesiac,0,1)=='0' || substr($miesiac,0,1)=='1') $stulecie = 1900;
if (substr($miesiac,0,1)=='8' || substr($miesiac,0,1)=='9') $stulecie = 1800;
if (substr($miesiac,0,1)=='2' || substr($miesiac,0,1)=='3') $stulecie = 2000;
if (substr($miesiac,0,1)=='5' || substr($miesiac,0,1)=='4') $stulecie = 2100;
if (substr($miesiac,0,1)=='6' || substr($miesiac,0,1)=='7') $stulecie = 2200;
if ($stulecie=='2000') $miesiac = $miesiac-20;
if ($stulecie=='1800') $miesiac = $miesiac-80;
if ($stulecie=='2100') $miesiac = $miesiac-40;
if ($stulecie=='2200') $miesiac = $miesiac-60;

// Ustalamy ostatecznie rok
$rok=$stulecie+substr($pesel,0,2);

// Zwracamy wynik
return array('rok'=>$rok, 'miesiac'=>$miesiac, 'dzien'=>$dzien);
}

Walidacja PESEL, jak widzisz, zawiera całkiem sporo logicznych warunków, które warto sprawdzać, ale to jeszcze nie koniec. Mamy na razie prawidłowy rok i miesiąc, a co z dniem?

Walidacja PESEL – czy taki dzień istnieje?

Należy, korzystając z wiedzy powyżej, „rozkodować” faktyczną datę, na którą wskazuje numer PESEL, a następnie sprawdzić, czy w ogóle jest możliwe, że ktokolwiek urodził się w takim dniu. Jak wspomniałem wcześniej, matematyczna walidacja PESEL zakłada algorytm, który bez problemu przyjmie datę np. 32 stycznia. Albo 29. lutego w roku, którym luty ma tylko 28 dni.

Zakładam, że na tym etapie znasz już pełną datę, zwróconą przy pomocy poprzedniej funkcji. Na szczęście nie ma konieczności budowania samodzielnie weryfikatora dnia, choć nie jest to zadanie wybitnie skomplikowane (powszechnie znane są liczby dni w miesiącach i tylko co 4 lata luty ma 29 dni). Istnieje odpowiednia funkcja natywna w PHP, która pozwala nam sprawdzić, czy w danym typie kalendarza dany dzień istnieje. Dla kalendarza gregoriańskiego wygląda to tak:

$maxDays = cal_days_in_month(CAL_GREGORIAN, $miesiac, $rok);

W zmiennej $maxDays uzyskamy liczbę dni, którą miał dany miesiąc w danym roku, co rozwiąże nam automatycznie problem 29. lutego.
Naturalnie w razie, jeśli liczba dni przekracza $maxDays – taki PESEL należy odrzucić jako nieprawdziwy. W pozostałych wypadkach mamy już pewność, że pierwsze 6 cyfr mówi o realnej dacie, istniejącej przynajmniej w kalendarzu.

Walidacja PESEL – na co jeszcze uważać?

To, że data jest realna, nie oznacza jeszcze końca walidacji numeru PESEL. Nie bez powodu wspominałem Ci o kilku stuleciach. Bez większych problemów, korzystając z generatorów, możesz wygenerować sobie numer PESEL zakładając datę urodzenia w latach, które jeszcze nie nadeszły!
Ponieważ jednak znasz już datę urodzenia wynikającą z PESEL możesz porównać ją z datą bieżącą wykonania skryptu. Przykładowo można to zrobić przy pomocy funkcji date_diff():

$interval =date_diff($dataAktualna, $dataPodana)->format('%R%a');

Metoda format (‘%R%a’) wykonana na obiekcie jak powyżej zwraca liczbę dni wraz z odpowiednim znakiem. Minus oznacza, że podana data jest z przeszłości, czyli prawidłowo. Znak dodatni oznacza, że podana data dopiero nadejdzie.

Korzystając z porównania dat możesz bez większego trudu określić wiek osoby, albo to, za jaki czas potencjalnie taka osoba się urodzi. Przydadzą Ci się takie formaty, jak %Y dla liczby lat, %m dla liczby miesięcy i %d dla liczby dni.

Walidacja PESEL rozbudowana o te elementy ma tę ciekawą właściwość, że dany PESEL każdego dnia może być zwalidowany inaczej, tj. może być dzisiaj uznany za niewiarygodny, ale za kilka miesięcy może być już wiarygodny.

Mając taką wiedzę o numerze PESEL, łatwo sprawdzisz:

  • Ile osoba ma lat
  • Za ile lat potencjalnie urodzi się ktoś, komu taki numer będzie mógł być nadany
  • Wychwycisz np. osoby niepełnoletnie
  • Wychwycisz np. PESEL’e osób w takim wieku, że można z wysokim prawdopodobieństwem przyjąć, że nie wypełniły Twojego formularza (np. więcej niż 100 lat, choć tu oczywiście jest pole do szerszej dyskusji, bo seniorzy coraz częściej aktywnie korzystają z internetu i zalecam wysoką ostrożność w stosowaniu takiej reguły).

Walidacja PESEL a imię

Cyfry od 7 o 10 to „numer seryjny”, ale nie jest to tak do końca kolejny numer urodzenia w danym dniu. Ostatnia cyfra koduje dodatkowo płeć. Nieparzyste są dla mężczyzn, parzyste dla kobiet. Wg mojej wiedzy nie są powszechnie znane szczególne reguły walidowania dla cyfr na pozycjach od 7 do 10. Pozostaje tu więc bazowanie na podstawowych kryteriach zakresu od 0 do 9 i zgodności z ostatnią, jedenastą cyfrą kontrolną.

Ponieważ jednak masz możliwość wnioskowania o płci osoby, do której należy PESEL, w języku polskim możesz pokusić się o porównanie podanego imienia z płcią. W wypadku fałszywych rejestracji istnieje większe prawdopodobieństwo, że dojdzie tutaj do niezgodności. Należy jednak pamiętać, że wnioskowanie o płci na podstawie imienia jest skuteczne tylko w większości przypadków.

Najprostszy sposób to wyciągniecie ostatniej litery imienia poleceniem substr($imie, -1) i sprawdzenie, czy jest to litera „a” – radykalna większość takich imion będzie oznaczać imię żeńskie.

Moda na nadawanie egzotycznych imion powoduje, że można spotkać osoby, których imiona nie będą dawały się w ten sposób sprawdzić. Co więcej, zdarza się, że np. mężczyzna posługuje się imieniem typowo kobiecym, np. Jan Maria. Istnieją też nieliczne wyjątki, np. Kuba – to imię męskie, a mimo to kończy się literą „a”.

Z tego powodu nie zalecam stopowania rejestracji czy blokowania IP użytkownika na podstawie niezgodności. Zalecam jednak oflagowanie takiej rejestracji, jako wymagającej dodatkowego, ręcznego sprawdzenia i osobiście traktowałbym taki rekord jako wymagający „szczególnej obserwacji”.

Walidacja PESEL – bezpłatne API

Jak widzisz, reguł jest sporo. Dlatego napisałem bezpłatne API, które umożliwi Ci sprawdzenie PESEL’u bez zastanawiania się, jak zaimplementować tę całą wiedzę w Twojej aplikacji. API zwraca informacje w formacie JSON, które łatwo wykorzystasz w dowolnym języku programowania.

Żeby zaoszczędzić Ci pracy po prostu jedynie odwołujesz się do API, a ono już robi całą resztę i zwraca wynik zawierający informację o tych wszystkich sprawdzeniach. Metoda działa w oparciu o wywołanie GET, nie wymaga autoryzacji użytkownika.

Api działa – na razie jest to wersja BETA – w oparciu o url:

https://h88.pl/sm/api/v1/

Zawiera endpoint:

pesel/verify

I wymaga parametru podanego metodą GET o nazwie PESEL. Metoda nie wymaga obecnie autoryzacji. Możesz więc sprawdzać sobie PESEL w swojej aplikacji bez żmudnego pisania kodu, po prostu odwołując się do naszego API:

https://h88.pl/sm/api/v1/pesel/verify/?pesel=87300369749

Dla takiego przykładowego wywołania uzyskasz zwrotkę w formacie JSON, która weryfikuje PESEL. W tym wypadku wygląda ona tak:

{
    "method": {
        "methodData": {
            "has11Digits": true,
            "isCheckSumOk": true,
            "isBirthDateValid": true,
            "bornAlready": false,
            "possibleBornInYears": 68,
            "possibleBornInMonths": 8,
            "possibleBornInDays": 9,
            "fullAge": false,
            "personSex": "F"
        },
        "methodStatus": "ok",
        "methodDetails": "ok"
    }
}

We wskazanej odpowiedzi z API widać, że walidacja PESEL zwróciła informację o numerze 87300369749 :

  • Jest poprawny w rozumieniu typu danych – zawiera 11 cyfr.
  • Jest poprawny z punktu widzenia algorytmu Luhna – tj. podstawowa metoda walidowania sumy kontrolnej daje wynik pozytywny. Stosowanie prostej walidacji tym algorytmem naraża zatem na przepuszczenie fałszywego numeru PESEL!
  • Zawiera poprawną datę urodzenia, tj taki dzień w kalendarzu istnieje.
  • Osoba o tym numerze PESEL nie jest pełnoletnia.
  • Osoba o tym numerze PESEL JESZCZE SIĘ NIE URODZIŁA!
  • Osoba o tym numerze PESEL potencjalnie może się urodzić za 68 lat, 8 miesięcy i 9 dni… i o więcej – jedynie DOKŁADNIE wtedy, ani dzień wcześniej, ani później.
  • Ten PESEL będzie należał do kobiety.

Teraz jako programista, rozumiejąc sens swojej aplikacji, sam możesz ocenić, czy interesuje Cię „przepuszczenie” rejestracji osoby, która dzisiaj posługuje się numerem PESEL kobiety, która być może urodzi się za 68 lat.

Zachęcam do zabawy i podstawiania różnych „dziwnych” numerów, aby sprawdzić, jak będzie wyglądać walidacja PESEL w różnych wypadkach.

Walidacja PESEL w PHP – gotowa klasa

Ponieważ po opublikowaniu artykułu kilka osób zwróciło mi uwagę, że czułyby się niekomfortowo korzystając z API, to przygotowałem gotowy kod całej klasy, wraz z przykładem wywołania. Tę klasę możesz sobie umieścić śmiało w Twoim projekcie. Korzystaj do woli.


$peselCheck = new peselChecker();
$peselStatus = $peselCheck->verify('87300369749');
var_dump($peselStatus);

Class peselChecker{

function verify($pesel){
	
// Kolejne metody zwracają kolejne cechy podanego numeru pesel

$this->pesel=$pesel;
	
$this->is11Integer();	// sprawdzenie czy ma 11 cyfr
$this->checkSum();		// sprawdzanie sumy kontrolnej
$this->verifyBirtDate();// sprawdzanie daty urodzenia
$this->getAge();		// obliczanie wieku
$this->getSex();		// określenie płci
	
return $this->returnResponse();

}

function is11Integer(){
	
// Czy składa sie z 11 cyfr

$this->response['has11Digits']=true;
if (!preg_match('/^[0-9]{11}$/', $this->pesel)) $this->response['has11Digits']=false;
		
}

function checkSum(){
		
// Klasyczna walidacja wg algorytmu Luhna z wagami stosowanymi przez MSWiA
// Na podstawie: http://phpedia.pl/wiki/Walidacja_numeru_PESEL

if (empty($this->response['has11Digits'])) return;

// tablica z odpowiednimi wagami

$arrWagi = array(1, 3, 7, 9, 1, 3, 7, 9, 1, 3); 
$intSum = 0;

//mnożymy każdy ze znaków przez wagę i sumujemy wszystko

for ($i = 0; $i < 10; $i++) {
	$intSum += $arrWagi[$i] * $this->pesel[$i]; 
}

//obliczamy sumę kontrolną i porównujemy ją z ostatnią cyfrą.

$int = 10 - $intSum % 10; 
$intControlNr = ($int == 10)?0:$int;

//sprawdzamy czy taka sama suma kontrolna jest w ciągu

if ($intControlNr == $this->pesel[10]){
	$this->response['isCheckSumOk']=true;
	return;
}

return  $this->response['isCheckSumOk']=false;

}

function verifyBirtDate(){
    
// Walidacja daty urodzenia wg istnienia dnia w kalendarzu
// Ze względu na działanie systemu PESEL na 5 stuleci
// dopisuje się 80, 20, 40, 60 do daty w odpowiednich stuleciach

if (empty($this->response['has11Digits'])) return;
	
//  Budowa tablicy możliwych wartości miesiąca	
	
$miesiac=substr($this->pesel,2,2);
$arrMiesiace = Array('01','02','03','04','05','06','07','08','09','10','11','12');
$arrDodatkoweMiesiace = Array(0,80,20,40,60);

foreach ($arrDodatkoweMiesiace as $miesiacDodatkowy){
	$arrMiesiaceBazowe = range(1,12);
	foreach ($arrMiesiaceBazowe as $miesiacBazowy){
		$arrMiesiace[]=$miesiacDodatkowy+$miesiacBazowy;
	}
}

if (!in_array($miesiac,$arrMiesiace)){
	$this->response['isBirthDateValid']=false;
	return;
}

// Ustalanie faktycznego miesiąca i stulecia

if (substr($miesiac,0,1)=='0' || substr($miesiac,0,1)=='1') $stulecie = 1900;
if (substr($miesiac,0,1)=='8' || substr($miesiac,0,1)=='9') $stulecie = 1800;
if (substr($miesiac,0,1)=='2' || substr($miesiac,0,1)=='3') $stulecie = 2000;
if (substr($miesiac,0,1)=='5' || substr($miesiac,0,1)=='4') $stulecie = 2100;
if (substr($miesiac,0,1)=='6' || substr($miesiac,0,1)=='7') $stulecie = 2200;

if ($stulecie=='2000') $miesiac = $miesiac-20;
if ($stulecie=='1800') $miesiac = $miesiac-80;
if ($stulecie=='2100') $miesiac = $miesiac-40;
if ($stulecie=='2200') $miesiac = $miesiac-60;

// Walidacja liczby dni w miesiącu

$rok=$stulecie+substr($this->pesel,0,2);
$maxDays = cal_days_in_month(CAL_GREGORIAN, $miesiac, $rok);

$dzien = substr($this->pesel,4,2);
$this->dataPodana = "$rok-$miesiac-$dzien";

if ($dzien > $maxDays){
	$this->response['isBirthDateValid']=false;
	return;
}
if ($dzien <=0){
	$this->response['isBirthDateValid']=false;
	return;
}
$this->response['isBirthDateValid']=true;
$this->response['birthDate']=date_format(date_create($this->dataPodana), 'Y-m-d');

}

function getAge(){

// Sprawdzenie wieku i daty urodzenia osoby, a także czy jest to osoba, która się jeszcze nie urodziła

if ($this->response['has11Digits']<>true) return;
if (empty($this->response['isBirthDateValid'])) return;

$dataAktualna	=date_create();
$dataPodana		=date_create($this->dataPodana);
$interval 		=date_diff($dataAktualna, $dataPodana)->format('%R%a');	// ile dni

if ($interval<0) {
	$this->response['bornAlready']=true;
	$this->response['personAgeYears']=-intval(date_diff($dataAktualna, $dataPodana)->format('%R%y'));
	$this->response['personAgeMonths']=-intval(date_diff($dataAktualna, $dataPodana)->format('%R%m'));
	$this->response['personAgeDays']=-intval(date_diff($dataAktualna, $dataPodana)->format('%R%d'));
	if ($this->response['personAgeYears']>=18) $this->response['fullAge']=true;
	if ($this->response['personAgeYears']<18)  $this->response['fullAge']=false;
}
if ($interval>0) {
	$this->response['bornAlready']=false;
	$this->response['possibleBornInYears']= intval(date_diff($dataAktualna, $dataPodana)->format('%y'));
	$this->response['possibleBornInMonths']=intval(date_diff($dataAktualna, $dataPodana)->format('%m'));
	$this->response['possibleBornInDays']=intval(date_diff($dataAktualna, $dataPodana)->format('%d'));
}

}

function getSex(){
	
// Sprawdzenie płci. 10 cyfra nieparzysta = mężczyzna, parzysta = kobieta
	
if ($this->response['has11Digits']<>true) return;
if (empty($this->response['isBirthDateValid'])) return;
$dziesiata = $this->pesel[9];
if (($dziesiata % 2 == 0)==true) {
	$this->response['personSex']='F';
	return;
}
$this->response['personSex']='M';
}

function returnResponse(){

return $this->response;
	
}

}

Walidacja PESEL – podsumowanie

Podsumowując zagadnienie walidacji PESEL w PHP widać, że zagadnienie wykracza poza prostą algorytmikę liczenia sumy kontrolnej, a skuteczna ochrona formularza wymaga nieco bardziej zaawansowanego sprawdzania, niż bazowanie wyłącznie na prostych regułach. Walidacja PESEL może być realizowana poprzez korzystanie z gotowego API zwracającego „porządnie” zwalidowany numer PESEL.

Walidacja PESEL jak najbardziej może być także wykonana lokalnie, np. bazując na powyższej, opublikowanej przeze mnie klasie.

Jak bardzo jest to dla Ciebie interesujące? Przyda Ci się ta wiedza? Masz czasem potrzebę sprawdzenia poprawności numeru PESEL? Podziel się tym artykułem ze znajomymi, zapraszam Cię także do dyskusji w komentarzu.

Artur Pajkert z kubkiem cyber_Folks
>
Artur Pajkert
Od 18 lat dzieli się wiedzą i poradami w sprawach e-marketingu i hostingu, jako menedżer, autor publikacji, prelegent, bloger, wykładowca akademicki.

11 odpowiedzi do "Walidacja PESEL w PHP"

  1. rob006 pisze:

    No super pomysł żeby wysyłać PESELe swoich użytkowników do jakiegoś zewnętrznego API, które nie wiadomo co z tym robi. Proponuję napisać jeszcze walidator siły hasła, żeby ludzie mogli tak samo wysyłać hasła swoich użytkowników i sprawdzać czy są wystarczająco mocne. 😉

    1. Artur Pajkert pisze:

      Rozumiem Twoje obiekcje. Piszą ten artykuł i to API wiedziałem, że ono nigdzie tego numeru nie zapisuje, nawet nie zwraca samego numeru, jedynie informację walidacyjną. Użytkownik z zewnątrz jednak tego po prostu nie wie i nie musi mi wcale wierzyć na słowo. Powierzając swoje dane – bazy – firmie hostingowej, udostępniasz o wiele szerszy zakres danych, więc korzystanie z API, które w te dane nie ingeruje, nie zapisuje, wydaje się przy tym niespecjalnym ryzykiem. Sytuację można jednak postrzegać inaczej, kiedy dostawca API jest Twoim dostawcą hostingu i masz z nim umowę powierzenia przetwarzania danych osobowych, a inaczej, kiedy nie jest. Dlatego uzupełniłem artykuł o gotową klasę walidacyjną w PHP, którą każdy może sobie zaimplementować lokalnie w swoim projekcie.

  2. rob006 pisze:

    Piszą ten artykuł i to API wiedziałem, że ono nigdzie tego numeru nie zapisuje

    A ja strzelam w ciemno że webserwer loguje wszystkie żądania do serwera i zapisuje adresy URL. A ponieważ PESEL jest wysyłany w GET, jest również zapisywany w logach. 🙂

    Poza tym cały sens takiej walidacji jest wątpliwy, a wstęp to już w ogóle zahacza o groteskę. Wygenerowanie fałszywego ale walidowalnego numeru PESEL to kwestia mniej niż minuty, zabezpieczenia tego typu są nie więcej niż symboliczne – zwykle wystarczy sprawdzenie sumy kontrolnej aby chronić się przed literówkami. Zanim ktoś się zacznie bawić w taką zaawansowaną walidację proponowałbym się zastanowić po co w ogóle przetwarzać PESEL – jest naprawdę niewiele sytuacji gdy ma to jakiś uzasadniony powód.

  3. Zgadzam się z rob006. Pomijam to czy jest sens walidowac PESEL ale wysyłanie danych do kogoś obcego? Nie robiłbym tego.
    Co do samej klasy to chyba przydałby się „sonar” 😉 Porównywanie z typem, [] zamiast array, nazwy zmiennych po polsku, a angielskie w response…
    Wiem, że to miało jedynie coś pokazać ale róbmy to też dobrze 🙂

    1. Artur Pajkert pisze:

      Dzięki za zwrócenie uwagi na tę kwestię i zgadzam się – warto będzie to poprawić.

  4. Tomek pisze:

    Świetny artykuł – dobra robota.

    Co do krytyki – daj Polakowi sztabkę złota to będzie narzekał że ciężka i nieporęczna 🙂

  5. Marecki pisze:

    Witam.
    Dla preg_match proponuje użycie takiego paternu:
    [0-9]{4}[0-3]{1}[0-9]{6}
    da nam to walidację dnia, który nie może być większy od liczby 3.
    Pozdrawiam.

  6. Kubson pisze:

    W jaki sposób można użyć powyższej metody walidacji PESEL w formularzu CF7?

    1. Artur Pajkert pisze:

      Wprawdzie nie ma na to „gotowca”, ale możesz użyć własnego filtra:
      https://contactform7.com/2015/03/28/custom-validation/ Sprawdź także więcej przykładów tutaj: https://stackoverflow.com/questions/22858288/contact-form-7-custom-validation
      Wystarczyłoby wówczas wpiąć proponowaną przede mnie procedurę wewnątrz takiej funkcji. Pod drugim linkiem jest przykład zaawansowanego walidowania maili, myślę, że to może być dobra inspiracja.

  7. Pers0n44 pisze:

    Dlaczego 88-latek też jest niepełnoletni?

  8. @R pisze:

    Przy poprawnym numerze pesel zawsze zwraca full age na false

Dodaj komentarz

Twój adres e-mail nie będzie opublikowany.

Polecane dla Ciebie

Szukasz dalej?