Format Credit Card with X's and Dashes using PHP (credit card masking)
I recently had a project where I needed to accomplish the following two tasks:
- Replace all but the last four digits of a credit card with X's
- Format the credit card with dashes in the appropriate places
There are many different approaches that can be taken to accomplish the above two tasks. The simplest approach would be to do something like the following:
<?php echo 'XXXX-XXXX-XXXX-'.substr($cc,-4); ?>
I have often seen credit cards masked with the above approach. For the most case this solution will work fairly well. However, I am not a huge fan of this approach as it displays the credit card at a fixed length of 16 digits. This can be a bit confusing since credit cards can very in length from 13 to 16 digits.
To better address this issue I put together two functions. One function is to apply a mask to a credit card and the other is to format the credit card with dashes. These functions will keep the original length of each credit card.
<?php
/**
* Replaces all but the last for digits with x's in the given credit card number
* @param int|string $cc The credit card number to mask
* @return string The masked credit card number
*/
function MaskCreditCard($cc){
// Get the cc Length
$cc_length = strlen($cc);
// Replace all characters of credit card except the last four and dashes
for($i=0; $i<$cc_length-4; $i++){
if($cc[$i] == '-'){continue;}
$cc[$i] = 'X';
}
// Return the masked Credit Card #
return $cc;
}
/**
* Add dashes to a credit card number.
* @param int|string $cc The credit card number to format with dashes.
* @return string The credit card with dashes.
*/
function FormatCreditCard($cc)
{
// Clean out extra data that might be in the cc
$cc = str_replace(array('-',' '),'',$cc);
// Get the CC Length
$cc_length = strlen($cc);
// Initialize the new credit card to contian the last four digits
$newCreditCard = substr($cc,-4);
// Walk backwards through the credit card number and add a dash after every fourth digit
for($i=$cc_length-5;$i>=0;$i--){
// If on the fourth character add a dash
if((($i+1)-$cc_length)%4 == 0){
$newCreditCard = '-'.$newCreditCard;
}
// Add the current character to the new credit card
$newCreditCard = $cc[$i].$newCreditCard;
}
// Return the formatted credit card number
return $newCreditCard;
}
?>
Below are a couple examples of how to use these functions and the results they create.
<?php
echo maskCreditCard('5362267121053405').'<br>'; // Prints XXXXXXXXXXXX3405
echo formatCreditCard('5362267121053405').'<br>'; // Prints 5362-2671-2105-3405
echo formatCreditCard(maskCreditCard('5362267121053405')).'<br>'; // Prints XXXX-XXXX-XXXX-3405
?>
<?php
$creditCard[] = '5362267121053405'; // Mastercard
$creditCard[] = '4556189015881361'; // Visa 16
$creditCard[] = '4716904617062'; // Visa 13
$creditCard[] = '372348371455844'; // American Express
$creditCard[] = '6011757892594291'; // Discover
$creditCard[] = '30329445722959'; // Diners Club
$creditCard[] = '214927124363421'; // enRoute
$creditCard[] = '180012855304868'; // JCB 15
$creditCard[] = '3528066275370961'; // JCB 16
$creditCard[] = '8699775919'; // Voyager
for($i=0;$i<count($creditCard);$i++)
{
echo FormatCreditCard(MaskCreditCard(($creditCard[$i])))."\n";
}
?>
Output:
XXXX-XXXX-XXXX-3405 XXXX-XXXX-XXXX-1361 X-XXXX-XXXX-7062 XXX-XXXX-XXXX-5844 XXXX-XXXX-XXXX-4291 XX-XXXX-XXXX-2959 XXX-XXXX-XXXX-3421 XXX-XXXX-XXXX-4868 XXXX-XXXX-XXXX-0961 XX-XXXX-5919
Let me know if you find these functions useful or have any suggestions on how to tweak them.
Tags: credit card, masking, php

June 24th, 2010 at 8:53 am
I like your formatting options with adding the dashes.
If you're looking for a one-line solution to keep the length and dashes exactly as entered:
preg_replace('/(?!^.?)[0-9](?!(.){0,3}$)/', '*', '3456-7890-1234-5678')
Keeps the FIRST CHARACTER, the LAST FOUR CHARACTERS, and any NON-NUMERIC CHARACTERS in-between. Masks (*) everything else.
"3456-7890-1234-5678" = "3***-****-****-5678"
"4567890123456789" = "4***********6789"
"4928-abcd9012-3456" = "4***-abcd****-3456"
"498291842" = "4****1842"
If the regular expression is a bit confusing, (?!) is a "look-ahead not-equals", meaning make sure this does NOT come before or next, but leave it alone.
October 19th, 2010 at 6:50 am
Hi.
I am trying something different from what you describe here, but maybe you have some help for me.
I have a string with 12 numbers and want to insert a dash after each fourth string.
So that
ABCDEFGHIJKLMNOP
turns into
ABCD-EFGH-IJKL-MNOP
Do you have a hint for me?
Thanks a lot in advance.
October 19th, 2010 at 7:06 am
Hi again… I solved my problem using my brain about 5 minutes… Sorry If you spent time on this!