Reputation: 71
I have a form on my website and my customers send message to me with this form. Sometimes they write their credit card number on the message. So this is really critical. I want to mask these credit card numbers. But of course card numbers don't come on a regular basis.
Example 1: 1111222233334444
Example 2: 4444 3333 2222 1111
Example 3: 4444-3333-2222-1111
Example 4: 4444 - 3333 - 2222 - 1111
Example 5: 4444--3333--2222--1111
So I can mask for example 1, 2 and 3. But if there are more than one space or dash between numbers I can't.
And this is my last regex:
preg_replace("/(?:\b| )([3456]\d{3})([ -]+){0,1}\d{4}([ -]+){0,1}\d{4}([ -]+){0,1}(\d{0})/", "$1********$2", $a1);
And results for this regex:
Result 1: 4444********1111
Result 2: 4444******** 1111
Result 3: 4444********-1111
Result 4: 4444******** - 1111
Result 5: 4444********--1111
So what should I do in regex? Thanks.
Upvotes: 4
Views: 23680
Reputation: 1
function maskCreditCard(cardNo) {
const cardNum = cardNo.replaceAll(" " ,"").replaceAll("-" ,"");
const last = cardNum.slice(-4)
return last.padStart(cardNum.length ,"*");
}
console.log(maskCreditCard("1111222233334444"));
console.log(maskCreditCard("4444 3333 2222 1111"));
console.log(maskCreditCard("4444-3333-2222-1111"));
console.log(maskCreditCard("4444 - 3333 - 2222 - 1111"));
console.log(maskCreditCard("4444--3333--2222--1111"));
Upvotes: 0
Reputation: 16105
How to mask credit card number mask in a text [with regex]?
Sometimes they write their credit card number on the message.
They really shouldn't. Don't encourage this behavior. It is not PCI compliant:
What is PCI Compliance?
The Payment Card Industry Data Security Standard (PCI DSS) applies to companies of any size that accept credit card payments. If your company intends to accept card payment, and store, process and transmit cardholder data, you need to host your data securely with a PCI compliant hosting provider.
When you accept credit card data via a website, do so using an approved service provider like Stripe, PayPal, BlueSnap, SecurionPay, etc. These services are immensely popular not because it's hard to make payment systems, but because they're hard to make right (and legal). They all have PHP API's, so you can have people enter credit card data that you never see, and still charge them for amounts that you agree upon.
For example, if you were using Stripe and you wish to inform your customer what credit card they signed up with, their card
object has a last4
property that gives the last four digits of the card: At this point you never knew the full credit card number, and you didn't even have to consider whether giving the first four and the last four was a security violation.
Never store electronic track data or the card security number in any form
While you may have a business reason for storing credit card information, processing regulations specifically forbid the storage of a card’s security code or any “track data” contained in the magnetic strip on the back of a credit card.
The card security number, called by many acronyms including CVV2, CID, and CSC, is the three digit number on the back of Visa/MasterCard/Discover cards or the 4 digit number on the front of American Express cards. It is designed to provide a way for merchants to know whether a customer authorizing a transaction over the phone or via the Internet actually has the card in their possession. This approach only works if the security code is never stored with the card number. Electronic storage makes this easy. You simply do not create a field for the security code. For paper storage, you need to redact (cross out with a dark pen to make unreadable) the security code after you successfully process the transaction and before you store a paper authorization form. [...]
Clearly you should store neither security codes nor track data purposely. But, you need to make sure you don’t store it inadvertently as well. To do this, be certain to use only approved hardware and software. [...]
Make sure all electronic storage of credit card account numbers is encrypted and all paper storage is secured
[...] Electronic storage of credit card numbers is also common if, for example, you process recurring or repeat transactions. If you do this, you need to make certain that you never store these files unencrypted. You need to make certain that any electronic storage is encrypted using a robust encryption algorithm. That way, if your computer is stolen or if someone in your office gains unauthorized access, you have some level of protection for the credit card numbers.
There are many service providers that offer secure storage—either as a standalone service or as part of a payment processing package. These services typically provide you with a “Token” for a card number they store. You can store the token in any unsecured file. When you’re ready to process a payment, you simply send the service provider the token and it retrieves the full card number for the sole purpose of processing the payment. (It’s technically more complicated than that, but you get the idea.) Just be certain to use a PCI DSS Verified provider [...]
Upvotes: 5
Reputation: 3429
Check the next regex \b([3-6]\d{3})(?: *-* *\d{4}){2} *-* *(\d{4})\b
.
Upvotes: 0
Reputation: 521419
May I suggest that you separate validation of your credit card number from the presentation of that number to your users via the UI? Assuming you have only stored valid credit card numbers, then it is probably safe to assume that every number has at least 8 digits. If so, then you can just use a blanket regex to only display the first 4 and last 8 digits:
$cc = "4444--3333--2222--1111";
echo preg_replace("/(\d{4}).*(\d{4})/", "$1********$2", $cc);
4444********1111
You might point out that this puts the same number of stars in between every card number. But, then again, this is a good thing, because it makes it even harder for a snooper to fish out what the real unmasked number actually is.
Edit:
Here is a smarter regex which will star out the middle portion of any number, leaving only the first and last 4 characters visible:
$cc = "4444--3333--2222--1111";
echo preg_replace("/(?<=.{4}).(?=.{4})/", "*", $cc);
4444**************1111
Note that this solution would not remove anything from 11114444
as a theoretical input.
Upvotes: 7