クレジットカード番号の入力誤り確認について
クレジットカードの入力フォームを作る時に使ったライブラリで、 DinersClubの番号が対応されていなかったので修正してみた。
修正の検証で、試しにDinersClubの番号を適当に入力したらエラーになった。
テスト用のカード番号 3056 930902 5904
だとエラーにならないけど、
3056 930902 5914
にすると何でエラーになるんだろう...? と少し考えた後に、
クレジットカード番号の入力誤りチェックにはLuhnアルゴリズムが使われていることを思いだした。
クレジットカードの番号は ISO/IEC 7812 で仕様が決められていて、 1から6桁目までは発行者を識別するための番号、 最後の1桁をチェックデジット(誤り確認のための数字)として使用している。
Luhnアルゴリズム
- 一の位から数えて奇数番目の場合はそのまま、偶数番目の場合は数を2倍する
- 2倍にした偶数番目の数が10以上の場合は、その各桁を足して1桁にする
- 例) 18 の 場合は 1 + 8 = 9 とする
- 得られた桁の数を全部足す
- 10で割り切れれば正当な番号
チェックデジットのサンプル
WEB+DB PRESS Vol.76 のWeb決済入門で紹介されていた、 サンプルを参考にして実際にテストしてみた。
- 作者: 五十嵐啓人,伊野亘輝,近藤宇智朗,渡邊恵太,須藤耕平,中島聡,A-Listers,はまちや2,川添貴生,片山育美,池田拓司,濱崎健吾,佐藤太一,曾川景介,久保渓,門脇恒平,登尾徳誠,伊藤直也,mala,後藤秀宣,若原祥正,奥野幹也,大林源,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2013/08/24
- メディア: 大型本
- この商品を含むブログを見る
Luhnアルゴリズムで番号を検証
class Luhn def self.check_number(number) reversed_numbers = number.reverse number_characters = reversed_numbers.chars number_characters.each_with_index.map{ |ch, index| # 0番目から数えて偶数番目の時(1桁目から数えた場合は奇数になる) if index.even? ch.to_i else x2 = ch.to_i * 2 (x2) % 10 + (x2) / 10 end }.inject(:+) % 10 == 0 end end
テストを書いて実行してみる
require 'test/unit' require_relative 'luhn' class TC_Luhn < Test::Unit::TestCase def test_luhn_valid assert_equal(Luhn.check_number("30569309025904"), true) end def test_luhn_invalid assert_equal(Luhn.check_number("30569309025914"), false) end end
30569309025904
はテスト用のカード番号で、
30569309025914
はわざと番号を間違えたものです。
実行結果
ruby test_luhn.rb Loaded suite test_luhn Started .. Finished in 0.000691 seconds. ------------------------------------------------------------------------------------------------------------------------------- 2 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed ------------------------------------------------------------------------------------------------------------------------------- 2894.36 tests/s, 2894.36 assertions/s
実行結果を見ると 30569309025914
はカード番号を間違えているので、
Luhn.check_number()
の返り値は false となる。