Archive - Originally posted on "The Horse's Mouth" - 2008-10-14 10:40:32 - Graham Ellis
It's standard practise for on line bookings these days to take credit or debit card details as a booking security, and we're no exception at Well House Manor - our hotel for business visitors to Melksham, Wiltshire. There are very many security issues involved, and I am not going to describe what we can and must do behind the scenes ourselves - rather, I'm going to show you the algorithm that checks that a card number's of the correct format in PHP.
Credit card numbers are typically 16 digits long, although some such as AmEx are a little shorter. The initial digit(s) tell you what type of card you're dealing with - the code below has the current set to the best of my knowledge, but you should check - and then all the digits are taken individually and combined into what is in effect a checksum value. If the checksum comes out as an exact multiple of 10, the number is potentially valid. If the checksum does not come out as a multiple of 10, then you can be sure the number is wrong.
The algorithm used is a clever one that's designed to make it very unlikely that a simple error in giving a credit card number (such as leaving a digit out, getting a digit wrong, or transposing two digits) is very unlikely indeed to lead you to a different valid number. Only in the case of two errors of these types does the probability of an error resulting in a valid code start approaching the 1 in 10 you might expect from a random error.
<?php
/* Some test code!
$ccwrong = array("4xxx xxxx xxxx 1123","4xxx xxxx xxxx 1716");
$ccright = array("4xxx xxxx xxxx 1715","4xxx xxxx xxxx 1111");
foreach (array_merge($ccwrong,$ccright) as $cc) {
list ($type,$valid,$cz) = ccvalidate($cc);
print ("Card $cc is $type and ".($valid?"OK":"Duff")."\n");
}
*/
# Function to take in a credit card number and identify type
# also check the check digits
function ccvalidate($ccno) {
# 1. Is is the right no. of digits (allowing commonly places spaces and dashes)
$card = "";
if (preg_match('/^\s*4\d{3}[-\s]*\d{4}[-\s]*\d{4}[-\s]*\d{4}\s*$/',$ccno)) {
$card = "Visa"; }
if (preg_match('/^\s*5[1-5]\d{2}[-\s]*\d{4}[-\s]*\d{4}[-\s]*\d{4}\s*$/',$ccno)) {
$card = "MC"; }
if (preg_match('/^\s*6011[-\s]*\d{4}[-\s]*\d{4}[-\s]*\d{4}\s*$/',$ccno)) {
$card = "Discover"; }
if (preg_match('/^\s*3[47](\d\s*){13}$/',$ccno)) {
$card = "AmEx"; }
if (preg_match('/^\s*3[068](\d\s*){12}$/',$ccno)) {
$card = Diners; }
# 2. Does the checksum work out?
# Get rid of none-digits
$ccno = preg_replace('/\D/','',$ccno);
$checksum = 0;
for ($i=strlen($ccno)-1; $i>=0 ; $i-=2) {
# Last digit, and alternate digits before it
$checksum += $ccno[$i];
# Other digits
if ($i) {
$digit = 2 * $ccno[$i-1];
$checksum += ($digit < 10) ? $digit : $digit-9;
}
}
return (array($card,$checksum%10 == 0 && $card != "",$checksum));
}
Online booking starts with https protocol rather that http as you'll find if you use our booking systems. This is one of my few bits of code that I am *not* going to put in my "demo" directory for you to try out - as that would be starting to teach you insecure ways by example.
Our PHP Techniques Workshop does cover aspects of accepting credit and debit cards online, and you can book hotel rooms in Melksham and public training course places via our sites. If you're looking for a private course, there are so many ways that we can tailor our training that we want to talk about your requirements before you book, so we don't have a completely automated, human intervention free, system.
The illustrations with this post show bedrooms 4 (top) and 3 (lower) at Well House Manor, where we offer accommodation for visitors to the town of Melksham. Our facilities are designed for the business traveller, but others are welcome too - all rooms are double or twin (but are usually let for single occupancy), there is internet access available 24 x 7, plenty of power points, large screen TVs with some 50 channels ... all rooms are en suite, there's tea, coffee and soft drinks available all day, every day ... and all these things which are often extras are included in the price, as is a breakfast of freshly squeezed orange juice, fruit, cereal, yoghurt, bread, toast and croissants, ham and cheese, jams and marmalade.