Tilinumeron tarkistaminen

uffis 30.09.04 22:58

Tarkistaa suomalaisen tilinumeron Luhnin modulo 10 -menetelmällä eli laskemalla tarkistusnumeron annetusta tilinumerosta ja vertaamalla laskettua tarkistusnumeroa tilinumerosta löytyvään. Tilinumerossa ei tarvitse olla väliviivaa.

 Tekstiversio  Arvo: 8 (10 ääntä)  Äänestä: +  -
<?php

/*
  Tarkistaa suomalaisen tilinumeron Luhnin modulo 10 -menetelmällä eli
  laskemalla tarkistusnumeron annetusta tilinumerosta ja vertaamalla
  laskettua tarkistusnumeroa tilinumerosta löytyvään. Tilinumerossa ei
  tarvitse olla väliviivaa.

  Lähde:

  http://www.pankkiyhdistys.fi/sisalto/upload/pdf/tilinrorakenne.pdf

  uffis @ 2004-10-02
*/

function tarkistaTilinumero($tilinumero)
{
  // Tarkistetaan, että alkuosa on aina 6 numeroa ja loppuosa 2-8 numeroa,
  // väliviiva ei ole pakollinen.
  if (!preg_match('/^\d{6}\-?\d{2,8}$/', $tilinumero))
    return false;

  // Poistetaan väliviiva alku- ja loppuosien välistä.
  $tmp_tilinumero = str_replace('-', '', $tilinumero);

  // Tarkistetaan, että tilinumeron alku on hyväksyttävä.
  if (!preg_match('/^(1|2|31|33|34|36|37|4|5|6|8)/', $tmp_tilinumero))
    return false;

  $alkuosan_pituus = 0;

  switch ($tmp_tilinumero{0})
  {
    // Ryhmä 1: tilinumerot 999999-99999 => 999999-00099999
    case 1:
    case 2:
    case 3:
    case 6:
    case 8:
      $alkuosan_pituus = 6;
      break;
    // Ryhmä 2: tilinumerot 999999-99999 => 999999-90009999
    case 4:
    case 5:
      $alkuosan_pituus = 7;
      break;
    default:
      return false;
  }

  define('TILINUMERON_PITUUS', 14);

  // Otetaan osat erilleen, lisätään etunollat ja yhdistetään osat.
  $alkuosa = substr($tmp_tilinumero, 0, $alkuosan_pituus);
  $loppuosan_pituus = TILINUMERON_PITUUS - $alkuosan_pituus;
  $loppuosa = str_pad(substr($tmp_tilinumero, $alkuosan_pituus),
    $loppuosan_pituus, '0', STR_PAD_LEFT);
  $tmp_tilinumero = $alkuosa . $loppuosa;

  $summa = 0;

  // Ensimmäisten 13 merkin painotukset eli kertoimet.
  $kertoimet = array(2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2);

  for ($i = 0; $i < TILINUMERON_PITUUS - 1; $i++)
  {
    $valisumma = $tmp_tilinumero{$i} * $kertoimet[$i];

    if ($valisumma >= 10)
    {
      // Lasketaan kaksinumeroisen tulon numerot yhteen.
      $jakojaannos = $valisumma % 10;
      $summa += $jakojaannos;
      $valisumma -= $jakojaannos;
      $summa += $valisumma / 10;
    }
    else
    {
      $summa += $valisumma;
    }
  }

  // Tarkistusnumero on summan erotus seuraavasta täydestä kymmenestä.
  $tarkistusnumero = 10 - ($summa % 10);
  if ($tarkistusnumero == 10)
    $tarkistusnumero = 0;

  return ($tarkistusnumero == $tmp_tilinumero{TILINUMERON_PITUUS - 1});
}

$tilinumero = '311234-561'; // oikea
//$tilinumero = '311234561'; // oikea
//$tilinumero = '123456-12343'; // oikea
//$tilinumero = '123456-12345'; // väärä

if (tarkistaTilinumero($tilinumero))
{
  echo 'Tilinumero on kunnossa.';
}
else
{
  echo 'Tilinumerossa on virhe.';
}
?>

chiman 10:51 2.10.04 
Ihan pätevältä tuo näyttää yhtä kohtaa lukuunottamatta. Voisit tarkistaa kolmosella alkavat tilinumerot tarkemmin, sillä niistä vain 31-, 33-, 34-, 36- tai 37-alkuiset voivat olla ok. Lisätietoja omassa skriptissäni.

Koodasin nimittäin saman skriptin Pythonilla; se löytyy täältä. Sen lisääminen omaksi koodipätkäkseen tänne olisi turhaa, mutta tuolta sen näkee, jos kiinnostaa.
uffis 15:55 2.10.04 
Kiitoksia huomiosta. Käyttämäni lähde ei ollut eritellyt alkuja noin tarkasti, enkä tohkeissani huomannut tarkistaa pankkiyhdistyksen sivuilta.

Tein seuraavia korjauksia:
- tarkistaa, että alkuosassa on tasan kuusi numeroa ja että loppuosassa 2-8 numeroa
- tarkistaa, että alku on hyväksyttävä
- muutin merkkijonon indeksoinnin käyttämään aaltosulkeita hakasulkeiden sijaan
- muutin kertoimien käytön taulukoksi sekä
- muutin painotuksen käymään merkkijonon alusta loppuun
sysrq868 12:34 5.2.05 
uffis kirjoitti:
Tilinumerossa ei tarvitse olla väliviivaa.


Mutta VOIKO siinä olla?
En tutkinut koodia sen pahemmin.
uffis 09:29 4.4.05 
Voi, mikä käy ilmi funktion ensimmäiseltä riviltä.