php validera personnummer ÅÅÅÅMMDD-XXXX

Permalänk
Medlem

php validera personnummer ÅÅÅÅMMDD-XXXX

ValidateSSN():

function ValidateSSN($pnr){ $pnr = trim($pnr); $rejection = NULL; $pnr = preg_replace("/[^0-9]/", "", $pnr); if (strlen($pnr)!=12){ if (strlen($pnr) == 10){ $pnr = "19".$pnr; } else{ $rejection = Rejections("3"); goto post; } } //echo $pnr; $pnr = substr($pnr, 2); if (checkPnr($pnr)) { $svar = "rätt"; if (strlen($pnr)!=13){ if (strlen($pnr) == 10){ $pnr = "19".substr($pnr,0,6)."-".substr($pnr,6,4); }elseif(strlen($pnr) == 12){ $pnr = substr($pnr,0,8)."-".substr($pnr,8,4); }else{ $rejection = Rejections("3"); goto post; } } } else { $svar = "fel"; //echo 'FEL!'; $rejection = Rejections("4"); } //} }

checkpnr():

function checkPnr($pnr) { /*if ( !preg_match("/^\d{8}\-\d{4}$/", $pnr) ) { return false; } $pnr = str_replace("-", "", $pnr);*/ $n = 2; for ($i=0; $i<9; $i++) { $tmp = $pnr[$i] * $n; ($tmp > 9) ? $sum += 1 + ($tmp % 10) : $sum += $tmp; ($n == 2) ? $n = 1 : $n = 2; } return !( ($sum + $pnr[9]) % 10); }

denna kod som jag länkat använder jag för att validera ÅÅMMDDXXXX, men nu vill jag validera ÅÅÅÅMMDD-XXXX.
normalt skickar jag in ÅÅÅÅMMDD-XXXX därför måste jag göra om allt innan jag skickar den till checkpnr(), men är inte alltid säkert att jag gör det. dock spelar det ingen roll.
jag vet att funktionen returnerar ÅÅÅÅMMDD-XXXX, men jag vill att den använder det, inte ÅÅMMDD-XXXX.
kan någon hjälpa mig med att antingen göra så den funkar eller hjälpa med en ny?

Visa signatur

Min dator: Silent Base 600 | 1700X @ 3.9Ghz | MSI Gaming X 1080TI | RM750X | 512Gb M2 | 16Gb 3200mhz Ram | S34E790C @ 3440x1440
Tjejens dator: Define r4 | i5 3570k @ 4.2ghz | GTX Titan | 750w Supernova | 240gb SSD | 32gb ram
Citera/Tagga för svar!

Permalänk
Hedersmedlem

@Christley:

Bara för att vara lite petig med namngivning så validering av SSN BÖR vara en faktiskt validering (aka ett korrekt personnummer) och inte bara "inga bokstäver"

Vidare, spalta upp ditt problem till en tydligare frågeställning och gör därefter din kod steg för steg fast i bara kommentarer, typ såhär

/** * Function to validateSSN (number only) and see if it's correct * * @param int $ssn * * @return bool */ function validateSSN($ssn) { $result = false; // Trim any spaces surrounding text // Regex pattern that checks if starting with 19/20 (or any), has 6 following digits, a (or no) dash "-" and 4 ending digits // Like: (19|20)?\d{6}-?{4} // Check if input matced regex return $result; }

Typ något sånt tänker jag,
den där regexen skrev jag i huvudet så inte säkert att den fungerar, men jag tror programmeringstekniken framgår.
Tydliggör vad du vill att funktionen ska göra, och överarbeta inte kod om du inte prompt måste.

Tex:
if (strlen($pnr)!=13){
Kollar ju bara om strängen inte är 13 tecken, det spelar ju inte roll om den är kortare eller längre, när den i själva verket vore helt felaktig om den vore längre, right?

Lycka till
(Vill du testa regexpatterns rekommenderar jag https://regex101.com/ om du inte har det i en IDE eller på annat håll)

Visa signatur

Dator, MOBO: Asus X99-A, CPU: Intel I7 6800k (3.4GHz), GPU: Geforce PNY 2070 Super, RAM: 4x8GB Corsair Vengeance LPX 2400MHz, OS-HDD: Intel 750 PCIe 400GB, PSU: EVGA SuperNOVA G2 850W

Permalänk
Medlem

@Klorixx skall du validera noga bör du väl i så fall även räkna på kontrollsiffra?

Permalänk
Medlem
Skrivet av Klorixx:

@Christley:

Bara för att vara lite petig med namngivning så validering av SSN BÖR vara en faktiskt validering (aka ett korrekt personnummer) och inte bara "inga bokstäver"

Vidare, spalta upp ditt problem till en tydligare frågeställning och gör därefter din kod steg för steg fast i bara kommentarer, typ såhär

Typ något sånt tänker jag,
den där regexen skrev jag i huvudet så inte säkert att den fungerar, men jag tror programmeringstekniken framgår.
Tydliggör vad du vill att funktionen ska göra, och överarbeta inte kod om du inte prompt måste.

Tex:
if (strlen($pnr)!=13){
Kollar ju bara om strängen inte är 13 tecken, det spelar ju inte roll om den är kortare eller längre, när den i själva verket vore helt felaktig om den vore längre, right?

Lycka till
(Vill du testa regexpatterns rekommenderar jag https://regex101.com/ om du inte har det i en IDE eller på annat håll)

koden har jag skrivit för 2 år sedan och då kunde jag knappt php, det är först nu jag återkommer till den.
och jag fattar inte regex överhuvudtaget. tycker det är onödigt klumpigt och svårt.
och saken är att jag inte kan spalta upp det i kommentarer. för då blir det bara
-> ta personnummer
-> räkna om det är korrekt.

om det följer med något, om det är för långt eller liknande så kommer den ändå aldrig validera korrekt så därför har jag aldrig brytt mig om att lägga till en validering. det är ändå bara jag som använder programmet.
och din validering är endast om det är korrekt uppbyggt. det räknar inte om det är ett korrekt personnummer. så 19900000-0000 hade gått igenom

Visa signatur

Min dator: Silent Base 600 | 1700X @ 3.9Ghz | MSI Gaming X 1080TI | RM750X | 512Gb M2 | 16Gb 3200mhz Ram | S34E790C @ 3440x1440
Tjejens dator: Define r4 | i5 3570k @ 4.2ghz | GTX Titan | 750w Supernova | 240gb SSD | 32gb ram
Citera/Tagga för svar!

Permalänk
Hedersmedlem
Skrivet av Tino:

@Klorixx skall du validera noga bör du väl i så fall även räkna på kontrollsiffra?

Absolut, det var precis det jag försökte komma fram till med mitt inlägg men insåg att det blev otydligt och kladdigt i koden.
Men jag menar att ska man "validera" ett personnummer bör det räknas ut att det är korrekt, medans detta bara validerar ett format.

Skrivet av Christley:

[...] för då blir det bara
-> ta personnummer
-> räkna om det är korrekt.
[...]

Och om dina kommentarer bara blir så skulle jag säga att det är där du bör träna isf. "lös problemet" är ju aldrig en lösning. Fortsätt hela tiden vidarutveckla. Läs högt för dig själv, blogga eller skriv på forum som nu (vet flertalet, inkl. jag själv som kommer på lösningen av att försöka tydligt beskriva ett problem).

Skrivet av Christley:

[...]din validering är endast om det är korrekt uppbyggt. det räknar inte om det är ett korrekt personnummer. så 19900000-0000 hade gått igenom

Yes, jag missade att du gjorde det i din kod, utan jag tolkade det mest som lite kluddrig kod (all kod utan kommentarer hoppar jag för det mesta över mycket i) som kollade att formatet var korrekt.

Min poäng med det hela är: tydliggör vad du vill ha gjort. Visa exempel. vad SKA fungera kontra vad ska INTE fungera.

Visa signatur

Dator, MOBO: Asus X99-A, CPU: Intel I7 6800k (3.4GHz), GPU: Geforce PNY 2070 Super, RAM: 4x8GB Corsair Vengeance LPX 2400MHz, OS-HDD: Intel 750 PCIe 400GB, PSU: EVGA SuperNOVA G2 850W

Permalänk
Medlem
Skrivet av Christley:

koden har jag skrivit för 2 år sedan och då kunde jag knappt php, det är först nu jag återkommer till den.
och jag fattar inte regex överhuvudtaget. tycker det är onödigt klumpigt och svårt.
och saken är att jag inte kan spalta upp det i kommentarer. för då blir det bara
-> ta personnummer
-> räkna om det är korrekt.

om det följer med något, om det är för långt eller liknande så kommer den ändå aldrig validera korrekt så därför har jag aldrig brytt mig om att lägga till en validering. det är ändå bara jag som använder programmet.
och din validering är endast om det är korrekt uppbyggt. det räknar inte om det är ett korrekt personnummer. så 19900000-0000 hade gått igenom

^(19|20)?[0-9]{2}[01][0-9][0-3][0-9]-[0-9]{4}$

Inte provat, men tycker det borde fungera.

Permalänk
Skrivet av kronwalled:

^(19|20)?[0-9]{2}[01][0-9][0-3][0-9]-[0-9]{4}$

Inte provat, men tycker det borde fungera.

Ditt regex godkänner månad 19 och dag 39. Det funkar ju lite beroende på hur noga man vill/behöver vara. Helst skall man väl se till att februari bara kan ha 29 dagar de år det är skottår... Men det är kanske lite overkill?

Skickades från m.sweclockers.com

Permalänk
Inaktiv
Skrivet av Lakritsugglan:

Ditt regex godkänner månad 19 och dag 39. Det funkar ju lite beroende på hur noga man vill/behöver vara. Helst skall man väl se till att februari bara kan ha 29 dagar de år det är skottår... Men det är kanske lite overkill?

Skickades från m.sweclockers.com

Aldrig prövat regex, men man kan väl köra lite av en fulvariant och göra en per månad, sedan dra ut månaden från servern och då köra den regexen som är lämplig?

Permalänk
Medlem

Jag har starkt för mig att validering av personnummer varit på tapeten innan och att någon kom då med det briljanta förslaget att använda språkets egna sträng-till-datum-funktion för att validera den delen. Då behöver man inte själv hålla kolla på om det är skottår o.dyl. Antingen går det att tolka som ett datum eller inte...

Och bara för att vara extra jobbig, så tänkte jag påpeka att det inte bara är minus-tecken som är tillåtet mellan datum- och nummer-delen av ett personnummer, utan även plus-tecken är giltigt. Detta används dock bara av personer som passerat den respektabla åldern av 100 år!

Visa signatur

as far as we can tell, the massacre went well...

Permalänk
Medlem
Skrivet av KaffeMedKotlett:

Aldrig prövat regex, men man kan väl köra lite av en fulvariant och göra en per månad, sedan dra ut månaden från servern och då köra den regexen som är lämplig?

Februari har 29 dagar om årtalet (gregoriansk kalender) är delbart med 4 men inte 100 om det även inte är delbart med 400. Det är omöjligt att beskriva en sådan match med regex.

Skrivet av jovnas:

Jag har starkt för mig att validering av personnummer varit på tapeten innan och att någon kom då med det briljanta förslaget att använda språkets egna sträng-till-datum-funktion för att validera den delen. Då behöver man inte själv hålla kolla på om det är skottår o.dyl. Antingen går det att tolka som ett datum eller inte...

#15817915

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Legendarisk

// https://www.skatteverket.se/privat/folkbokforing/personnummer... // https://sv.wikipedia.org/wiki/Personnummer_i_Sverige class Personnummer { private $year = null, $month = null, $day = null, $bn = null; public function __construct($year, $month, $day, $bn) { $this->year = $year; $this->month = $month; $this->day = $day; $this->bn = $bn; } public static function validateString($personnummer) { return self::createFromString($personnummer) !== null; } public static function createFromString($personnummer) { // Ett personnummer består av 6 siffror (yymmdd), ett skiljetecken som är antingen ett bindestreck // eller ett plustecken (i de fall personen är 100 eller äldre), ett tre siffror långt // födelsenummer och en kontrollsiffra. // // Som tidigare påpekats så kan vi inte använda regjuljära uttryck för att validera numret // eftersom att vi även måste kontrollera att det är ett giltigt datum samt verifiera // att kontrollsiffran stämmer, men vi kan använda det för att kontrollera textformatet // och dela upp det i användbara delar: if(preg_match("/^ (\d{2}) # 1: År (\d{2}) # 2: Månad (\d{2}) # 3: Dag ([+-]) # 4: Skiljetecken (\d{3}) # 5: Födelsenummer (\d{1}) # 6: Kontrollsiffra $/x", $personnummer, $m)) { $year = (int)$m[1]; $month = (int)$m[2]; $day = (int)$m[3]; $sep = $m[4]; $bn = (int)$m[5]; $check = (int)$m[6]; // Innan vi kan kontrollera datumet så måste vi normalisera födelseåret: $year = self::normalizeYear($year, $sep === "+"); // Sedan kan vi kontrollera att datumet är giltigt, // PHP har en standardfunktion för syftet, använd den: if(checkdate($month, $day, $year)) { // Sedan verifierar vi kontrollsiffran: if($check === self::calcCheckDigit($year, $month, $day, $bn)) { return new self($year, $month, $day, $bn); } } } return null; } private static function normalizeYear($birthYear, $hundredOrOlder = false) { $currentYear = (int)date("Y"); $currentCentury = floor($currentYear / 100) * 100; $currentYear = $currentYear % 100; if($hundredOrOlder) { if($birthYear > $currentYear) { return $birthYear + $currentCentury - 200; } else { return $birthYear + $currentCentury - 100; } } else { if($birthYear > $currentYear) { return $birthYear + $currentCentury - 100; } else { return $birthYear + $currentCentury; } } } private static function calcCheckDigit($year, $month, $day, $bn) { // Skapa en sträng med tvåsiffriga datumkomponenter och födelsenumret: $digits = sprintf( '%02d%02d%02d%03d', substr((string)$year, 2, 2), $month, $day, $bn ); $sum = 0; // För varje tecken... for($i = 0, $c1 = strlen($digits); $i < $c1; ++$i) { // Multiplicera siffran omväxlande med 1 eller 2: $t = (string)((int)$digits[$i] * ($i % 2 === 0 ? 2 : 1)); // För varje siffra i resultatet: for($n = 0, $c2 = strlen($t); $n < $c2; ++$n) { // Addera till summan: $sum += (int)$t[$n]; } } // Hämta resten och subtrahera den från 10: $check = 10 - $sum % 10; // Om resten är 10 så blir kontrollsiffran 0: return $check === 10 ? 0 : $check; } public function getYear() { return $this->year; } public function getMonth() { return $this->month; } public function getDay() { return $this->day; } public function getBirthNumber() { return $this->bn; } public function getGender() { return $this->bn % 2; } public function getCheckDigit() { return self::calcCheckDigit($this->year, $this->month, $this->day, $this->bn); } public function toString() { return sprintf( '%s%02d%02d%s%03d%d', substr((string)$this->year, 2, 2), $this->month, $this->day, ((int)date("Y") - $this->year < 100 ? "-" : "+"), $this->bn, $this->getCheckDigit() ); } public function __toString() { return $this->toString(); } } // Tester: var_dump( Personnummer::validateString("640823-3234"), // Exempel från Skatteverket Personnummer::validateString("811218-9876"), // Exempel från Wikipedia Personnummer::validateString("160207-0003"), // Idag Personnummer::validateString("160207+0003"), // Idag, för 100 år sedan Personnummer::validateString("040229-0001"), // På skottdagen 2004 Personnummer::validateString("100101+0006"), // Mer än hundra år gammal, född på 1900-talet Personnummer::validateString("900101+0009"), // Mer än hundra år gammal, född på 1800-talet Personnummer::validateString("000101-0008"), // 1:e januari 2000 Personnummer::validateString("000101+0008"), // 1:e januari 1900 Personnummer::validateString("640823-3233"), // Skatteverket (ogiltig kontrollsiffra) Personnummer::validateString("811218-9875"), // Wiki (ogitlig kontrollsiffra) Personnummer::validateString("030229-0002") // På skottdagen 2003 (giltig kontrollsiffra, ogiltigt datum) ); // Skapa nytt personnummer: $nyttPN = new Personnummer(1980, 2, 7, 000); var_dump($nyttPN->toString());

Exempel i PHP
Visa signatur

Abstractions all the way down.

Permalänk
Medlem
Skrivet av Lakritsugglan:

Ditt regex godkänner månad 19 och dag 39. Det funkar ju lite beroende på hur noga man vill/behöver vara. Helst skall man väl se till att februari bara kan ha 29 dagar de år det är skottår... Men det är kanske lite overkill?

Skickades från m.sweclockers.com

Så sant, kände mig tvungen att fila lite på det, tycker denna borde fungera (dock endast notepad för närvarande så någon parantes kan ha gått åt skogen):

^(19|20)?[0-9]{2}((0[13578]|1[02])(0[1-9]|[1-2][0-9]|3[01])|(0[469]|10)(0[1-9]|[1-2][0-9]|30)|02(?(?<=((19|20)(04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)|2000)02)(0[1-9]|[1-2][0-9])|(0[1-9]|1[0-9]|2[0-8])))-[0-9]{4}$

Kräver att användaren fyller i de första siffrorna i födelseåret (dvs 1988 inte 88) annars defaultar den till icke skottår's 28 dagars februari. Stod mellan det, eller än mer nestat regex, eller behandla år 1900 felaktigt som skottår (vilket ändå blir en gissningslek om användaren endast fyller i 00).

Permalänk
Medlem

FYI people, jag har löst detta och "stängt" tråden tidigare, men en mod har av någon anledning återställt mitt inlägg och sen tagit bort att jag har löst detta redan

@Tunnelsork:
även fast jag löst det så tänker jag testa detta, ser för bra ut för att inte kolla in de

Visa signatur

Min dator: Silent Base 600 | 1700X @ 3.9Ghz | MSI Gaming X 1080TI | RM750X | 512Gb M2 | 16Gb 3200mhz Ram | S34E790C @ 3440x1440
Tjejens dator: Define r4 | i5 3570k @ 4.2ghz | GTX Titan | 750w Supernova | 240gb SSD | 32gb ram
Citera/Tagga för svar!

Permalänk
Medlem
Skrivet av kronwalled:

^(19|20)?[0-9]{2}((0[13578]|1[02])(0[1-9]|[1-2][0-9]|3[01])|(0[469]|10)(0[1-9]|[1-2][0-9]|30)|02(?(?<=((19|20)(04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)|2000)02)(0[1-9]|[1-2][0-9])|(0[1-9]|1[0-9]|2[0-8])))-[0-9]{4}$

help

Visa signatur

AMD Ryzen 7 5800X | 32 GB Corsair Vengeance 3200 MHz | ASUS TUF Geforce RTX 3080

Permalänk
Medlem
Skrivet av L'ombra:

Kan man lungt säga, inte stiligt, finns ingen mening att använda det över ovan eleganta lösning för php-specifika ändamål. Men om man bara ska validera att input är giltig, oavsett språk (så länge stöd för lookbehind finns)...

Med stöd för +/- oavsett om århundrade anges, måste dock uppdateras årligen om man inte är villig att bygga ihop den med strings mha Date funktionalitet. Inte för att jag tror någon har nytta för det, men men.

^(19(?=((0[0-9]|1[0-6])[0-9]{4}\+))|(19(?=((1[7-9]|[2-9][0-9])[0-9]{4}-))|20(?=((0[0-9]|1[0-6])[0-9]{4}-))))?[0-9]{2}((0[13578]|1[02])(0[1-9]|[1-2][0-9]|3[01])|(0[469]|10)(0[1-9]|[1-2][0-9]|30)|02(?(?<=(04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)02|(?<=(0002))(?=(0[1-9]|[1-2][0-9])\+))(0[1-9]|[1-2][0-9])|(0[1-9]|1[0-9]|2[0-8])))[-+][0-9]{4}$

Permalänk
Medlem
Skrivet av Tunnelsork:

// https://www.skatteverket.se/privat/folkbokforing/personnummer... // https://sv.wikipedia.org/wiki/Personnummer_i_Sverige class Personnummer { private $year = null, $month = null, $day = null, $bn = null; public function __construct($year, $month, $day, $bn) { $this->year = $year; $this->month = $month; $this->day = $day; $this->bn = $bn; } public static function validateString($personnummer) { return self::createFromString($personnummer) !== null; } public static function createFromString($personnummer) { // Ett personnummer består av 6 siffror (yymmdd), ett skiljetecken som är antingen ett bindestreck // eller ett plustecken (i de fall personen är 100 eller äldre), ett tre siffror långt // födelsenummer och en kontrollsiffra. // // Som tidigare påpekats så kan vi inte använda regjuljära uttryck för att validera numret // eftersom att vi även måste kontrollera att det är ett giltigt datum samt verifiera // att kontrollsiffran stämmer, men vi kan använda det för att kontrollera textformatet // och dela upp det i användbara delar: if(preg_match("/^ (\d{2}) # 1: År (\d{2}) # 2: Månad (\d{2}) # 3: Dag ([+-]) # 4: Skiljetecken (\d{3}) # 5: Födelsenummer (\d{1}) # 6: Kontrollsiffra $/x", $personnummer, $m)) { $year = (int)$m[1]; $month = (int)$m[2]; $day = (int)$m[3]; $sep = $m[4]; $bn = (int)$m[5]; $check = (int)$m[6]; // Innan vi kan kontrollera datumet så måste vi normalisera födelseåret: $year = self::normalizeYear($year, $sep === "+"); // Sedan kan vi kontrollera att datumet är giltigt, // PHP har en standardfunktion för syftet, använd den: if(checkdate($month, $day, $year)) { // Sedan verifierar vi kontrollsiffran: if($check === self::calcCheckDigit($year, $month, $day, $bn)) { return new self($year, $month, $day, $bn); } } } return null; } private static function normalizeYear($birthYear, $hundredOrOlder = false) { $currentYear = (int)date("Y"); $currentCentury = floor($currentYear / 100) * 100; $currentYear = $currentYear % 100; if($hundredOrOlder) { if($birthYear > $currentYear) { return $birthYear + $currentCentury - 200; } else { return $birthYear + $currentCentury - 100; } } else { if($birthYear > $currentYear) { return $birthYear + $currentCentury - 100; } else { return $birthYear + $currentCentury; } } } private static function calcCheckDigit($year, $month, $day, $bn) { // Skapa en sträng med tvåsiffriga datumkomponenter och födelsenumret: $digits = sprintf( '%02d%02d%02d%03d', substr((string)$year, 2, 2), $month, $day, $bn ); $sum = 0; // För varje tecken... for($i = 0, $c1 = strlen($digits); $i < $c1; ++$i) { // Multiplicera siffran omväxlande med 1 eller 2: $t = (string)((int)$digits[$i] * ($i % 2 === 0 ? 2 : 1)); // För varje siffra i resultatet: for($n = 0, $c2 = strlen($t); $n < $c2; ++$n) { // Addera till summan: $sum += (int)$t[$n]; } } // Hämta resten och subtrahera den från 10: $check = 10 - $sum % 10; // Om resten är 10 så blir kontrollsiffran 0: return $check === 10 ? 0 : $check; } public function getYear() { return $this->year; } public function getMonth() { return $this->month; } public function getDay() { return $this->day; } public function getBirthNumber() { return $this->bn; } public function getGender() { return $this->bn % 2; } public function getCheckDigit() { return self::calcCheckDigit($this->year, $this->month, $this->day, $this->bn); } public function toString() { return sprintf( '%s%02d%02d%s%03d%d', substr((string)$this->year, 2, 2), $this->month, $this->day, ((int)date("Y") - $this->year < 100 ? "-" : "+"), $this->bn, $this->getCheckDigit() ); } public function __toString() { return $this->toString(); } } // Tester: var_dump( Personnummer::validateString("640823-3234"), // Exempel från Skatteverket Personnummer::validateString("811218-9876"), // Exempel från Wikipedia Personnummer::validateString("160207-0003"), // Idag Personnummer::validateString("160207+0003"), // Idag, för 100 år sedan Personnummer::validateString("040229-0001"), // På skottdagen 2004 Personnummer::validateString("100101+0006"), // Mer än hundra år gammal, född på 1900-talet Personnummer::validateString("900101+0009"), // Mer än hundra år gammal, född på 1800-talet Personnummer::validateString("000101-0008"), // 1:e januari 2000 Personnummer::validateString("000101+0008"), // 1:e januari 1900 Personnummer::validateString("640823-3233"), // Skatteverket (ogiltig kontrollsiffra) Personnummer::validateString("811218-9875"), // Wiki (ogitlig kontrollsiffra) Personnummer::validateString("030229-0002") // På skottdagen 2003 (giltig kontrollsiffra, ogiltigt datum) ); // Skapa nytt personnummer: $nyttPN = new Personnummer(1980, 2, 7, 000); var_dump($nyttPN->toString());

Exempel i PHP

har äntligen fått användning av en personnummer verifierare igen och måste säga att denna lösningen är guld. otroligt stark. tack som fan att du postade den

Visa signatur

Min dator: Silent Base 600 | 1700X @ 3.9Ghz | MSI Gaming X 1080TI | RM750X | 512Gb M2 | 16Gb 3200mhz Ram | S34E790C @ 3440x1440
Tjejens dator: Define r4 | i5 3570k @ 4.2ghz | GTX Titan | 750w Supernova | 240gb SSD | 32gb ram
Citera/Tagga för svar!

Permalänk
Medlem

För er som är intresserade, luhn algoritmen kallas den: https://sv.wikipedia.org/wiki/Luhn-algoritmen

Permalänk
Medlem

Om tråden ändå ligger såhär pass högt uppe i forumet som den ju nu gör just nu så kan jag ju påpeka att man inte nödvändigtvis ska vara så värst nitisk med vad man godkänner i födelsedelen av personnumret som en del inlägg ovan är. Som ett exempel; Det finns ju även av Skatteverket tilldelade samordningsnummer, som har 60 adderat på datumet, och det finns en hel del situationer då även personer med sådana istället för fullvärdiga personnummer kan ha nytta av att kunna matas in i diverse system.

(Och när jag ändå håller på - använd inte personnummer som primärnycklar i nån databas eller så om det går att undvika, de byts alldeles för ofta för att det ska vara så värst roligt att bygga på rutiner för det i efterhand)

Visa signatur

The power of GNU compiles you!
"Often statistics are used as a drunken man uses lampposts -- for support rather than illumination."

Permalänk
Legendarisk
Skrivet av Christley:

har äntligen fått användning av en personnummer verifierare igen och måste säga att denna lösningen är guld. otroligt stark. tack som fan att du postade den

Kul att det kom till användning!

Skrivet av kode:

Om tråden ändå ligger såhär pass högt uppe i forumet som den ju nu gör just nu så kan jag ju påpeka att man inte nödvändigtvis ska vara så värst nitisk med vad man godkänner i födelsedelen av personnumret som en del inlägg ovan är. Som ett exempel; Det finns ju även av Skatteverket tilldelade samordningsnummer, som har 60 adderat på datumet, och det finns en hel del situationer då även personer med sådana istället för fullvärdiga personnummer kan ha nytta av att kunna matas in i diverse system.

TIL. Det verkar dock vara en smal sak att testa för även sådana; om dagen > 60 så räkna bort det innan datumet valideras, resten av processen ser ut att vara densamma. Samordningsnummer beskrivs här:
https://www.skatteverket.se/foretagochorganisationer/myndighe...

Finns det fler, liknande undantag?

Här är ett exempel för PHP 7.1 som accepterar samordningsnummer:

<?php declare(strict_types=1); // https://www.skatteverket.se/privat/folkbokforing/personnummer... // https://www.skatteverket.se/foretagochorganisationer/myndighe... // https://sv.wikipedia.org/wiki/Personnummer_i_Sverige class Personnummer { private $year = 0, $month = 0, $day = 0, $bn = 0; public function __construct(int $year, int $month, int $day, int $bn) { $this->year = $year; $this->month = $month; $this->day = $day; $this->bn = $bn; } public static function validateString(string $personnummer) : bool { return self::createFromString($personnummer) !== null; } public static function createFromString(string $personnummer) : ?Personnummer { // Ett personnummer består av 6 siffror (yymmdd), ett skiljetecken som är antingen ett bindestreck // eller ett plustecken (i de fall personen är 100 eller äldre), ett tre siffror långt // födelsenummer och en kontrollsiffra. // // Som tidigare påpekats så kan vi inte använda regjuljära uttryck för att validera numret // eftersom att vi även måste kontrollera att det är ett giltigt datum samt verifiera // att kontrollsiffran stämmer, men vi kan använda det för att kontrollera textformatet // och dela upp det i användbara delar: if(preg_match("/^ (\d{2}) # 1: År (\d{2}) # 2: Månad (\d{2}) # 3: Dag ([+-]) # 4: Skiljetecken (\d{3}) # 5: Födelsenummer (\d{1}) # 6: Kontrollsiffra $/x", $personnummer, $m)) { $year = (int)$m[1]; $month = (int)$m[2]; $day = (int)$m[3]; $sep = $m[4]; $bn = (int)$m[5]; $check = (int)$m[6]; // Innan vi kan kontrollera datumet så måste vi normalisera födelseåret: $year = self::normalizeYear($year, $sep === "+"); // Sedan kan vi kontrollera att datumet är giltigt, // PHP har en standardfunktion för syftet, använd den. // // Om datumet > 60 så är det ett samordningsnummer; // subtrahera 60 från datumet innan kontrollen. if(checkdate($month, $day > 60 ? $day - 60 : $day, $year)) { // Sedan verifierar vi kontrollsiffran: if($check === self::calcCheckDigit($year, $month, $day, $bn)) { return new self($year, $month, $day, $bn); } } } return null; } private static function normalizeYear(int $birthYear, bool $hundredOrOlder = false) : int { $currentYear = (int)date("Y"); $currentCentury = (int)floor($currentYear / 100) * 100; $currentYear = $currentYear % 100; if($hundredOrOlder) { if($birthYear > $currentYear) { return $birthYear + $currentCentury - 200; } else { return $birthYear + $currentCentury - 100; } } else { if($birthYear > $currentYear) { return $birthYear + $currentCentury - 100; } else { return $birthYear + $currentCentury; } } } private static function calcCheckDigit(int $year, int $month, int $day, int $bn) : int { // Skapa en sträng med tvåsiffriga datumkomponenter och födelsenumret: $digits = sprintf( '%02d%02d%02d%03d', substr((string)$year, 2, 2), $month, $day, $bn ); $sum = 0; // För varje tecken... for($i = 0, $c1 = strlen($digits); $i < $c1; ++$i) { // Multiplicera siffran omväxlande med 1 eller 2: $t = (string)((int)$digits[$i] * ($i % 2 === 0 ? 2 : 1)); // För varje siffra i resultatet: for($n = 0, $c2 = strlen($t); $n < $c2; ++$n) { // Addera till summan: $sum += (int)$t[$n]; } } // Hämta resten och subtrahera den från 10: $check = 10 - $sum % 10; // Om resten är 10 så blir kontrollsiffran 0: return $check === 10 ? 0 : $check; } public function getYear() : int { return $this->year; } public function getMonth() : int { return $this->month; } public function getDay() : int { return $this->day; } public function getBirthNumber() : int { return $this->bn; } public function getGender() : int { return $this->bn % 2; } public function getCheckDigit() : int { return self::calcCheckDigit($this->year, $this->month, $this->day, $this->bn); } public function toString() : string { return sprintf( '%s%02d%02d%s%03d%d', substr((string)$this->year, 2, 2), $this->month, $this->day, ((int)date("Y") - $this->year < 100 ? "-" : "+"), $this->bn, $this->getCheckDigit() ); } public function __toString() : string { return $this->toString(); } } // Tester: header("Content-Type: text/plain"); // Validera personnummer: var_dump( // Alla dessa ska passera... Personnummer::validateString("640823-3234"), // Exempel från Skatteverket Personnummer::validateString("811218-9876"), // Exempel från Wikipedia Personnummer::validateString("160207-0003"), // Idag Personnummer::validateString("160207+0003"), // Idag, för 100 år sedan Personnummer::validateString("040229-0001"), // På skottdagen 2004 Personnummer::validateString("100101+0006"), // Mer än hundra år gammal, född på 1900-talet Personnummer::validateString("900101+0009"), // Mer än hundra år gammal, född på 1800-talet Personnummer::validateString("000101-0008"), // 1:e januari 2000 Personnummer::validateString("000101+0008"), // 1:e januari 1900 Personnummer::validateString("701063-2391"), // Samordningsnummer null, // Men inga av dessa... Personnummer::validateString("640823-3233"), // Skatteverket (ogiltig kontrollsiffra) Personnummer::validateString("811218-9875"), // Wiki (ogitlig kontrollsiffra) Personnummer::validateString("030229-0002") // På skottdagen 2003 (giltig kontrollsiffra, ogiltigt datum) ); // Generera personnummer: $a = new Personnummer(1964, 8, 23, 323); // Exempel från Skatteverket $b = new Personnummer(1970, 10, 63, 239); // Samordningsnummer var_dump([ $a->toString(), $b->toString() ]);

Dold text
Visa signatur

Abstractions all the way down.