Mask credit card number in PHP

前端 未结 11 1513
执笔经年
执笔经年 2020-12-09 13:19

I have credit card number which I want to mask as below:

$cc = 1234123412341234

echo cc_masking($cc)

1234XXXXXXXX1234

function cc_masking($number) {.....}         


        
相关标签:
11条回答
  • 2020-12-09 13:48

    With regular expression

    function cc_masking( $number, $maskChar = 'X' ) {
        return preg_replace(
            '/^(....).*(....)$/',
            '\1' . str_repeat( $maskChar, strlen( $number ) - 8) . '\2',
            $number );
    }
    

    You keep the first four characters (and the last four), replacing the others with X.

    0 讨论(0)
  • 2020-12-09 13:53

    No need for regular expression for this. Just take n numbers at the beginning, n numbers at the end then add the X in the middle to complete.

    0 讨论(0)
  • 2020-12-09 13:53

    If you wish to show only last 4 digits, here is a dynamic way. Works with both credit cards, ACH numbers or anything:

    https://gist.github.com/khoipro/815ea292e2e87e10771474dc2ef401ef

        $variable = '123123123';
        $length = strlen($variable);
        $output = substr_replace($variable, str_repeat('X', $length - 4), 0, $length - 4);
        echo $output;
    
    0 讨论(0)
  • 2020-12-09 14:08

    Assuming that:

    • Credit card numbers might be contained in a bigger string containing more content
    • All major credit cards are sum-checked using the Luhn algorithm https://en.wikipedia.org/wiki/Luhn_algorithm

    This is what I do:

    • I detect, via regex, if a string contains a chain of digits, separated or not by spaces and hyphens.
    • For every match, I strip it from non-numeric values and check if is a valid Luhn.
    • Replace the part I want, for every match, with replacement characters (usually "*").

    The code is this:

    public function mask($string)
    {
        $regex = '/(?:\d[ \t-]*?){13,19}/m';
    
        $matches = [];
    
        preg_match_all($regex, $string, $matches);
    
        // No credit card found
        if (!isset($matches[0]) || empty($matches[0]))
        {
            return $string;
        }
    
        foreach ($matches as $match_group)
        {
            foreach ($match_group as $match)
            {
                $stripped_match = preg_replace('/[^\d]/', '', $match);
    
                // Is it a valid Luhn one?
                if (false === $this->_util_luhn->isLuhn($stripped_match))
                {
                    continue;
                }
    
                $card_length = strlen($stripped_match);
                $replacement = str_pad('', $card_length - 4, $this->_replacement) . substr($stripped_match, -4);
    
                // If so, replace the match
                $string = str_replace($match, $replacement, $string);
            }
        }
    
        return $string;
    }
    

    You will see a call to $this->_util_luhn->isLuhn, which is a function that does this:

    public function isLuhn($input)
    {
    
        if (!is_numeric($input))
        {
            return false;
        }
    
        $numeric_string = (string) preg_replace('/\D/', '', $input);
    
        $sum = 0;
    
        $numDigits = strlen($numeric_string) - 1;
    
        $parity = $numDigits % 2;
    
        for ($i = $numDigits; $i >= 0; $i--)
        {
            $digit = substr($numeric_string, $i, 1);
    
            if (!$parity == ($i % 2))
            {
                $digit <<= 1;
            }
    
            $digit = ($digit > 9)
                ? ($digit - 9)
                : $digit;
    
            $sum += $digit;
        }
    
        return (0 == ($sum % 10));
    }
    

    It is how I implemented it in https://github.com/pachico/magoo/. Hope you find it useful.

    0 讨论(0)
  • 2020-12-09 14:10
    $accNum = "1234123412341234";
    
    $accNum1 = substr($accNum,2,2);
    
    $accNum1 = '**'.$accNum1;
    
    $accNum2 = substr($accNum,6,100);
    
    $accNum2 = '**'.$accNum2;
    
    $accNum = $accNum1.$accNum2;
    
    echo $accNum;
    
    0 讨论(0)
提交回复
热议问题