Avatar billede webudvikleren Nybegynder
27. september 2007 - 16:42 Der er 17 kommentarer

CPR-nummer-aldersbegrænsing

Hejsa. Jeg har set på adskillige spille-sider, at man skal være over 18 for at oprette sig som bruger. Dette script validerer med sit CPR-nummer.

Nogle der ved hvordan jeg kan lave ét som tjekker om man er over 16 år?

Ligesom ved her: http://www.bidster.com/t_new_user.php

På forhånd tak,
Jesper Kampmann Madsen
Avatar billede zerocrash Nybegynder
27. september 2007 - 16:59 #1
Nemt ;)

Tilføj følgende efter <body>-tagget

<script>
var minimumalder=16;

  function mod(value,modvalue){
      if(value<0) value*= -1;
      for(i=modvalue;i<value+modvalue;i+=modvalue){
        //alert(i+"/"+value);
        if(i>value){
            return (value-(i-modvalue));
        }
      }
  }

  function checkCPR_DK(cpr){

 
    faktor = "432765432";
    tempsum = 0;
    taeller = 1;
    //cpr = Replace(cpr, "-", "")
   
   

    if(cpr.length== 10){
      kontroltal = 1 * cpr.substring(cpr.length-1,cpr.length);
    // alert(kontroltal);
      // Hvis det indtastede cprnummer er netop 10 cifre langt, så gennemføres nedenstående løkke,
      // der checker gyldigheden af cprnummeret, ciffer for ciffer.
    // alert(cpr);
      while(taeller< 10){

            tegn =cpr.substring(taeller-1,taeller);
            Mult =faktor.substring(taeller-1,taeller);
          // alert(tegn+"/"+Mult);
            if (!isNaN(tegn)){

            // Hvis det indtastede tegn på pladsen som variablen taeller peger på er et tal,
            // så foretages beregningen af tempsum, og tælleren taeller forøges med 1

                tempsum = tempsum + (tegn * Mult);
                taeller++;
            }
            else{
           
            // Hvis der er indtastet et ugyldigt tegn i cprnummeret, meldes nedenstående fejl.
           
                alert("Du har indtastet et ugyldigt tegn");

           
          }
        }

        // Når tempsum endeligt er udregnet, checkes efter nedenstående model
   
        check = 11-mod(tempsum, 11);

        // Hvis check svarer til cprnummeret sidste ciffer (kontroltal), eller check = 11, er
        // cprnummeret gyldigt, og nedenstående meddelelse vises
        if(check == kontroltal|| check == 11){
       
            foedselsdag = cpr.substring(5,6);//Left(cpr, 6);
            serienummer = cpr.substring(cpr.length-4,cpr.length-3);//Right(cpr, 4);
            //alert(parseInt(cpr.substring(4,6))+"/"+parseInt(cpr.substring(2,4))+"/"+parseInt(cpr.substring(0,2)));
            //alert(parseInt(cpr.substring(4,6))+"/"+parseInt(cpr.substring(2,4))+"/"+cpr.substring(0,2));
            fDate=new Date(parseInt(cpr.substring(4,6)),parseInt(cpr.substring(2,4))-1,cpr.substring(0,2));   
            idag=new Date();
            return(idag-fDate)/31536000000;;
   
    return (idag-fDate)/31536000000;  //returner alder i år
            return true;
        }
        else{
   
        // Hvis foregående check fejler, er der tale om et ugyldigt cpr-nummer,
        // og nedenstående meddelelse vises
        return false;
        }
    }   
    else{
        return false;
    }
}

function checkCPR_NO(cpr){
    s=new Array();
    checkVAL = false;
    if (cpr.length!=11) return checkVAL;
    for(i=1;i<=11;i++)
        s[i] = parseInt(cpr.substring(i-1,i));
   
    K1 = s[1] * 3 + s[2] * 7 + s[3] * 6 + s[4] * 1 + s[5] * 8 + s[6] * 9 + s[7] * 4 + s[8] * 5 + s[9] * 2;
    K1 = mod(K1,11);
    if(K1==1) return checkVAL;
    if(K1!=0) K1 = 11 - K1;
    K2 = s[1] * 5 + s[2] * 4 + s[3] * 3 + s[4] * 2 + s[5] * 7 + s[6] * 6 + s[7] * 5 + s[8] * 4 + s[9] * 3 + K1 * 2;
    K2 = mod(K2,11);
    if(K2==1) return checkVAL;
    if(K2!=0) K2 = 11 - K2;
    if(s[10]!=K1) return checkVAL;
    if(s[11]!=K2)  return checkVAL;
    checkVAL = true;
   
    fDate=new Date(parseInt(s[5]+""+s[6]),parseInt(s[3]+""+s[4]),parseInt(s[1]+""+s[2]));   
    idag=new Date();
    //alert(idag-fDate);
   
    return (idag-fDate)/31536000000;  //returner alder i år
}

function checkCPR(){
  cpr=document.mainform.cpr.value;
  cpr=cpr.replace(/-/g,"");
  age_DK=checkCPR_DK(cpr);
  age_NO=checkCPR_NO(cpr); 
  //alert(age_DK+"/"+age_NO);
  if(age_DK<minimumalder&&age_NO<minimumalder)
    alert("De indtastede oplysninger giver ikke adgang til Adult Zone"); 
  else{
      alert("Gå til Adult Zone ...");
      document.location="10/9/8/adult.html";
  } 
 
  return(0);
}


</script>

-------------

Felt til indtastning af CPR kommer her:

    <FORM Name=mainform>

    <B><input type=button onclick=tast(); value="Indtast Cpr.nr. her"> </B> <INPUT size=12 type=hidden disabled name=cpr>
          <br>
          <br>
          <br>
         
    </FORM>
Avatar billede zerocrash Nybegynder
27. september 2007 - 17:01 #2
Hov nu så jeg ikke lige, at du ville have det i PHP - men håber at scriptet kan bruges anyway ;)
Avatar billede terrak Nybegynder
27. september 2007 - 19:24 #3
Her er en simpel version, som laver et svagt tjek af validiteten af selve CPR-nummeret, samt tester alderen. Det er testet, men jeg garanterer umiddelbart ikke at det er fejlfrit :-)

-----

function validCPR($cpr) {
$agemin = 18;
$control = array(4,3,2,7,6,5,4,3,2,1);
$controlsum = 0;

for ($i = 0; $i < count($control); $i++) {
$controlsum += $cpr[$i]*$control[$i];
}

if (strlen($cpr) == count($control) && $controlsum % 11 == 0) {
$age = (substr((date('Y')-$agemin),2,2).date('m').date('d') >= substr($cpr,4,2).substr($cpr,2,2).substr($cpr,0,2));
} else {
$age = false;
}

return $age;

}

-----

Funktionen bruges f.eks. således:

$mycpr = '2709894040';
if (validCPR($mycpr)) {
echo 'CPR ok';
} else {
echo 'CPR ikke ok';
}

(eksemplet vil godkende CPR nummeret 270989-4040 i dag d. 27/09-2007 og fremefter, men f.eks. ikke 280989-4048, da personen ikke er fyldt 18 endnu)

Jeg vil overveje at nægte brugeren flere forsøg, hvis CPR ikke valideres efter 2 gange. Hvis brugeren er under 18 og bruger et "falsk" cpr som brugeren selv finder på, skal personen nemlig ramme det rigtige kontrolciffer (det sidste, fra 0-9).
Jeg tror det er de færreste brugere (under 18) som vil tjekke at det sidste kontrolciffer er rigtigt. En bruger med et korrekt CPR nummer vil næppe taste det forkert igen, efter at have fået at vide at det ikke er korrekt indtastet.
Avatar billede webudvikleren Nybegynder
27. september 2007 - 19:49 #4
Tak for input zerocash!

Terrak - præcist! :D Fantastisk! Kast svar. Jeg vælger at dele points med zerocash, da jeg syntes han svar også er nyttigt. Kan nemmelig bruge jeres begge - til både php og javascript - så kast svar i 2 og et kæmpe tak igen
Avatar billede erikjacobsen Ekspert
27. september 2007 - 20:12 #5
Så vidt jeg kan se vil det afvise folk på 100 år og op. Læs mere om CPR-nummeret på www.cpr.dk
Avatar billede erikjacobsen Ekspert
27. september 2007 - 20:17 #6
Og iøvrigt vil den acceptere '2709014040'
Avatar billede zerocrash Nybegynder
27. september 2007 - 20:17 #7
Webudvikleren...

mange tak ;) Opdagede dog som sagt først bagefter du havde plantet ?'et i PHP - men igen, tak - hermed et svar.

Erikjacobsen - hvilket er der tale om? PHP-modellen?
Avatar billede yHec Novice
27. september 2007 - 20:19 #8
Jeg er sikker på, at Datatilsynet ikke synes det er en fatastisk idé, at du gemmer cpr-numre. De er faktisk at betragte som fortrolige data, som man skal have tilladelse til at opbevare! Og den får du ikke, idet du ikke har et retskrav mod dine brugere.

Nøjes med at gemme fødselsdagene, og et unikt bruger-id istedet.

Bare en tanke

/y
Avatar billede zerocrash Nybegynder
27. september 2007 - 20:22 #9
Y - før du nu udtaler dig vil jeg anbefale dig at tage et kig på javascriptet jeg smed her i tråden.

Det GEMMER ikke data fra CPR. Hverken fødselsdato eller kontrolcifre (de sidste 4 cifre). Den validerer om det indtastede nummer er korrekt og fører et kontrolcheck med det sidste kontrolciffer hvorefter det guider brugeren videre til den angivne side.

Det gemmer som sagt INTET. Og af hvad jeg kan se, gør PHP'en det heller ikke
Avatar billede terrak Nybegynder
27. september 2007 - 20:24 #10
erikjacobsen > Ja, det så jeg også lige, jeg ser om ikke jeg kan lave et script der gør brug af f.eks. mktime() i stedet for.
Derudover er alderen også 16, ikke 18 som jeg er gået ud fra.

y > Er du sikker på at webudvikleren vil gemme denne information, frem for bare at tjekke? Men ellers relevant nok :-)
Avatar billede yHec Novice
27. september 2007 - 20:36 #11
Jeg er ikke sikker på noget som helst... ;-)

Mener bare, at cpr-numret bliver misbrugt alt for meget. Personligt ville jeg aldrig logge på en ikke-officiel side, der udbad sig mit cpr. Hvis det ikke gemmes, hvorfor så spørge efter det, så burde fødsesdagen være nok. Jeg ved godt, at der er fordele ved at kunne validere med kontrolciffer mm. Men det er alligevel ved at blive afskaffet! Så man løber en risiko for, at et korrekt cprnummer valideres til ugyldigt, uden at være det!
Jvn www.cpr.dk

/y
Avatar billede zerocrash Nybegynder
27. september 2007 - 20:41 #12
Y - du har selvfølgelig ret i det. Jeg ville da også klart hellere validere (såfremt dette blev afkrævet!) via SSL end blot via en ukrypteret webside. Uanset om det så er pga. en XXX-side eller hvad det nu er - så er det da stadig personfølsomme data og man skal dog stadig gøre meget for, at undgå misbrug tiltrods for det "kun" er CPR.
Avatar billede terrak Nybegynder
27. september 2007 - 21:22 #13
Så er den omskrevet og delt op i to funktioner :-)

Ved min alder på 16:
2809914049 // nej
2709914041 // ja
2709014040 // nej

-----

function validCPR($cpr) {
$agemin = 16;
$control = array(4,3,2,7,6,5,4,3,2,1);

if (strlen($cpr) != count($control)) {
return false;
exit;
}

$controlsum = 0;
$cpryear = substr($cpr,4,2);
$cpryearfull = cpryearfull($cpr[6],$cpryear);
$cprmonth = substr($cpr,2,2);
$cprday = substr($cpr,0,2);


for ($i = 0; $i < count($control); $i++) {
$controlsum += $cpr[$i]*$control[$i];
}

if ($controlsum % 11 == 0 && checkdate($cprmonth,$cprday,$cpryearfull)) {
$age = ((date('Y')-$agemin).date('m').date('d') >= $cpryearfull.$cprmonth.$cprday);
} else {
$age = false;
}

return $age;

}

---

function cpryearfull($cpr7, $cpryear) {

$controlyear = array(
0 => array(19,19,19),
1 => array(19,19,19),
2 => array(19,19,19),
3 => array(19,19,19),
4 => array(20,19,19),
5 => array(20,0,18),
6 => array(20,0,18),
7 => array(20,0,18),
8 => array(20,0,18),
9 => array(20,19,19)
);

$controlyearindexes = array(37,58,99);

foreach ($controlyearindexes as $key => $value) {

if ($cpryear < $value) {
$controlyearindex = $key;
break;
}

}


if (!isset($controlyearindex) && $controlyear[$cpr7][$controlyearindex] != 0) {
return false;
} else {
return $controlyear[$cpr7][$controlyearindex].$cpryear;
}


}

-----

Nu er den dog ikke helt så simpel/overskuelig længere..
Avatar billede terrak Nybegynder
27. september 2007 - 22:17 #14
Lige en rettelse:
if (!isset($controlyearindex) && $controlyear[$cpr7][$controlyearindex] != 0) {
skal være
if (!isset($controlyearindex) || $controlyear[$cpr7][$controlyearindex] != 0) {
Første kontrol er lidt redundant, men det går nok.

Og lidt irrelevant: "Ved min alder på 16" skulle være "Ved min. alder på 16:" :-)
Avatar billede webudvikleren Nybegynder
28. september 2007 - 00:21 #15
Jeg vil selvfølgelig ikke gemme personernes cpr-nummer..

Terrak - hvad er forskellen på den nye og gamle? Kan ikke det matematiske i det der cpr-system, vil bare gerne have den bedste og mest sikreste tjekker i 2 forskellige eksempler.
Avatar billede terrak Nybegynder
28. september 2007 - 09:47 #16
Det ser nu ud til at der alligevel ikke skal laves modulus 11 tjekket:
http://www.cpr.dk/cpr/site.aspx?p=108&t=visartikel&Articleid=4347

Det første script jeg postede kunne ikke se forskel på om et personnummer med årstal 02 var født i 2002 eller 1902, det kan det andet. Derfor er det andet script at foretrække.

Hvis du vil undlade modulus 11 tjekket, skal du bare fjerne arrayet $control og ændre linjen
if ($controlsum % 11 == 0 && checkdate($cprmonth,$cprday,$cpryearfull)) {
til
if (checkdate($cprmonth,$cprday,$cpryearfull)) {

Det matematiske i CPR-nummeret er ikke så avanceret da man bare ganger en talrække på hvert tal i CPR-nummeret og dividerer summen med 11. Er der ingen rest er CPR-nummeret "korrekt". Du kan læse om det på http://da.wikipedia.org/wiki/CPR-nummer
Avatar billede zerocrash Nybegynder
10. juli 2011 - 00:20 #17
Skal vi få lukket? :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester