Checking a Credit Card Checksum
Problem
You want to know whether a credit card number was entered correctly.
Solution
The last digit of every credit card is a checksum digit. You can compare the other digits against the checksum to catch mistakes someone might make when typing their credit card number.
Lucas Carlson's CreditCard library, available as the creditcard gem, contains Ruby implementations of the checksum algorithms. It adds methods to the String and Integer classes to check the internal consistency of a credit card number:
require 'rubygems' require 'creditcard' '5276 4400 6542 1319'.creditcard? # => true '5276440065421313'.creditcard? # => false 1276440065421319.creditcard? # => false
CreditCard can also determine which brand of credit card a certain number is for:
5276440065421313.creditcard_type # => "mastercard"
Discussion
The CreditCard library uses a well-known algorithm for finding the checksum digit of a credit card. If you can't or don't want to install the creditcard gem, you can just implement the algorithm yourself:
module CreditCard def creditcard? numbers = self.to_s.gsub(/[^d]+/, '').split(//) checksum = 0 0.upto numbers.length do |i| weight = numbers[-1*(i+2)].to_i * (2 - (i%2)) checksum += weight % 9 end return numbers[-1].to_i == 10 - checksum % 10 end end class String include CreditCard end class Integer include CreditCard end '5276 4400 6542 1319'.creditcard? # => true
How does it work? First, it converts the object to an array of numbers:
numbers = '5276 4400 6542 1319'.gsub(/[^d]+/, '').split(//) # => ["5", "2", "7", "6", "4", "4", "0", "0", # => "6", "5", "4", "2", "1", "3", "1", "9"]
It then calculates a weight for each number based on its position, and adds that weight to a running checksum:
checksum = 0 0.upto numbers.length do |i| weight = numbers[-1*(i+2)].to_i * (2 - (i%2)) checksum += weight % 9 end checksum # => 51
If the last number of the card is equal to 10 minus the last digit of the checksum, the number is self-consistent:
numbers[-1].to_i == 10 - checksum % 10 # => true
A self-consistent credit card number is just a number with a certain mathematical property. It can catch typos, but there's no guarantee that a real credit card exists with that number. To check that, you need to use a payment gateway like Authorize.net, and a gateway library like Payment::AuthorizeNet.
See Also
- Recipe 16.8, "Charging a Credit Card"