代码之家  ›  专栏  ›  技术社区  ›  Joe Lencioni

用PHP验证信用卡的最佳方法是什么?

  •  66
  • Joe Lencioni  · 技术社区  · 16 年前

    给定一个信用卡号,并且没有其他信息,在PHP中确定它是否为有效数字的最佳方法是什么?

    现在我需要的东西,将与美国运通,发现,万事达卡和签证,但它可能会有帮助,如果它也将与其他类型的工作。

    9 回复  |  直到 16 年前
        1
  •  154
  •   Mike    10 年前

    卡号验证分为三个部分:

    1. 图案 -是否符合发卡机构模式(如VISA/Mastercard等)
    2. 校验和
    3. 真的存在 -它实际上是否有关联帐户(如果没有商户帐户,您不太可能获得此帐户)

    • VISA前缀=4,长度=13或16(Mod10)
    • 美国运通前缀=34或37,长度=15(Mod10)
    • 就餐者俱乐部/点菜前缀=300-305,36或38,长度=14(Mod10)
    • 等等( detailed list of prefixes )

    校验和

    大多数卡对校验和使用Luhn算法:

    Luhn Algorithm described on Wikipedia

    <?
    /* Luhn algorithm number checker - (c) 2005-2008 shaman - www.planzero.org *
     * This code has been released into the public domain, however please      *
     * give credit to the original author where possible.                      */
    
    function luhn_check($number) {
    
      // Strip any non-digits (useful for credit card numbers with spaces and hyphens)
      $number=preg_replace('/\D/', '', $number);
    
      // Set the string length and parity
      $number_length=strlen($number);
      $parity=$number_length % 2;
    
      // Loop through each digit and do the maths
      $total=0;
      for ($i=0; $i<$number_length; $i++) {
        $digit=$number[$i];
        // Multiply alternate digits by two
        if ($i % 2 == $parity) {
          $digit*=2;
          // If the sum is two digits, add them together (in effect)
          if ($digit > 9) {
            $digit-=9;
          }
        }
        // Total up the digits
        $total+=$digit;
      }
    
      // If the total mod 10 equals 0, the number is valid
      return ($total % 10 == 0) ? TRUE : FALSE;
    
    }
    ?>
    
        2
  •  30
  •   Nisse Engström sting_roc    10 年前

    从…起 10 regular expressions you can't live without in PHP :

    function check_cc($cc, $extra_check = false){
        $cards = array(
            "visa" => "(4\d{12}(?:\d{3})?)",
            "amex" => "(3[47]\d{13})",
            "jcb" => "(35[2-8][89]\d\d\d{10})",
            "maestro" => "((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?)",
            "solo" => "((?:6334|6767)\d{12}(?:\d\d)?\d?)",
            "mastercard" => "(5[1-5]\d{14})",
            "switch" => "(?:(?:(?:4903|4905|4911|4936|6333|6759)\d{12})|(?:(?:564182|633110)\d{10})(\d\d)?\d?)",
        );
        $names = array("Visa", "American Express", "JCB", "Maestro", "Solo", "Mastercard", "Switch");
        $matches = array();
        $pattern = "#^(?:".implode("|", $cards).")$#";
        $result = preg_match($pattern, str_replace(" ", "", $cc), $matches);
        if($extra_check && $result > 0){
            $result = (validatecard($cc))?1:0;
        }
        return ($result>0)?$names[sizeof($matches)-2]:false;
    }
    

    样本输入:

    $cards = array(
        "4111 1111 1111 1111",
    );
    
    foreach($cards as $c){
        $check = check_cc($c, true);
        if($check!==false)
            echo $c." - ".$check;
        else
            echo "$c - Not a match";
        echo "<br/>";
    }
    

    这给了我们

    4111 1111 1111 1111 - Visa
    
        3
  •  13
  •   PartialOrder    15 年前

    最好不要在代码中进行验证。将卡信息直接发送到您的支付网关,然后处理他们的回复。如果你不先做Luhn检查之类的事情,它可以帮助他们发现欺诈——让他们看到失败的尝试。

        4
  •  6
  •   Patrick Desjardins    16 年前

    PHP代码

    function validateCC($cc_num, $type) {
    
        if($type == "American") {
        $denum = "American Express";
        } elseif($type == "Dinners") {
        $denum = "Diner's Club";
        } elseif($type == "Discover") {
        $denum = "Discover";
        } elseif($type == "Master") {
        $denum = "Master Card";
        } elseif($type == "Visa") {
        $denum = "Visa";
        }
    
        if($type == "American") {
        $pattern = "/^([34|37]{2})([0-9]{13})$/";//American Express
        if (preg_match($pattern,$cc_num)) {
        $verified = true;
        } else {
        $verified = false;
        }
    
    
        } elseif($type == "Dinners") {
        $pattern = "/^([30|36|38]{2})([0-9]{12})$/";//Diner's Club
        if (preg_match($pattern,$cc_num)) {
        $verified = true;
        } else {
        $verified = false;
        }
    
    
        } elseif($type == "Discover") {
        $pattern = "/^([6011]{4})([0-9]{12})$/";//Discover Card
        if (preg_match($pattern,$cc_num)) {
        $verified = true;
        } else {
        $verified = false;
        }
    
    
        } elseif($type == "Master") {
        $pattern = "/^([51|52|53|54|55]{2})([0-9]{14})$/";//Mastercard
        if (preg_match($pattern,$cc_num)) {
        $verified = true;
        } else {
        $verified = false;
        }
    
    
        } elseif($type == "Visa") {
        $pattern = "/^([4]{1})([0-9]{12,15})$/";//Visa
        if (preg_match($pattern,$cc_num)) {
        $verified = true;
        } else {
        $verified = false;
        }
    
        }
    
        if($verified == false) {
        //Do something here in case the validation fails
        echo "Credit card invalid. Please make sure that you entered a valid <em>" . $denum . "</em> credit card ";
    
        } else { //if it will pass...do something
        echo "Your <em>" . $denum . "</em> credit card is valid";
        }
    
    
    }
    

    用法

    echo validateCC("1738292928284637", "Dinners");
    

    更多理论信息可在此处找到:

    Credit Card Validation - Check Digits

    Checksum

        5
  •  3
  •   Dana    16 年前

    luhn algorithm 是一种校验和,可用于验证许多信用卡格式(以及加拿大社会保险号码…)的格式

    维基百科的文章还链接到许多不同的实现;下面是一个PHP示例:

    http://planzero.org/code/bits/viewcode.php?src=luhn_check.phps

        6
  •  2
  •   powtac    16 年前

    有一个PEAR软件包,用于处理许多财务数字的验证,以及信用卡验证: http://pear.php.net/package/Validate_Finance_CreditCard

    Test Credit Card Account Numbers

        7
  •  0
  •   parkamark    9 年前

    只是加入一些其他人可能会发现有用的代码片段(不是PHP代码)。

    python (单行代码;可能效率不高)

    要验证:

    >>> not(sum(map(int, ''.join(str(n*(i%2+1)) for i, n in enumerate(map(int, reversed('1234567890123452'))))))%10)
    True
    >>> not(sum(map(int, ''.join(str(n*(i%2+1)) for i, n in enumerate(map(int, reversed('1234567890123451'))))))%10)
    False
    

    要返回所需的校验位,请执行以下操作:

    >>> (10-sum(map(int, ''.join(str(n*(i%2+1)) for i, n in enumerate(map(int, reversed('123456789012345')), start=1)))))%10
    2
    >>> (10-sum(map(int, ''.join(str(n*(i%2+1)) for i, n in enumerate(map(int, reversed('234567890123451')), start=1)))))%10
    1
    

    MySQL函数

    功能“ccc”和“ccd”(信用卡检查和信用卡数字)

    请注意,“ccc”函数有一个附加检查,如果计算的和为0,返回的结果将始终为假,因此全零CC编号将永远不会验证为正确(在正常行为下,它将正确验证)。可根据需要添加/删除此功能;根据具体要求,可能有用。

    DROP FUNCTION IF EXISTS ccc;
    DROP FUNCTION IF EXISTS ccd;
    
    DELIMITER //
    
    CREATE FUNCTION ccc (n TINYTEXT) RETURNS BOOL
    BEGIN
      DECLARE x TINYINT UNSIGNED;
      DECLARE l TINYINT UNSIGNED DEFAULT length(n);
      DECLARE i TINYINT UNSIGNED DEFAULT l;
      DECLARE s SMALLINT UNSIGNED DEFAULT 0;
      WHILE i > 0 DO
        SET x = mid(n,i,1);
        IF (l-i) mod 2 = 1 THEN
          SET x = x * 2;
        END IF;
        SET s = s + x div 10 + x mod 10;
        SET i = i - 1;
      END WHILE;
      RETURN s != 0 && s mod 10 = 0;
    END;
    
    CREATE FUNCTION ccd (n TINYTEXT) RETURNS TINYINT
    BEGIN
      DECLARE x TINYINT UNSIGNED;
      DECLARE l TINYINT UNSIGNED DEFAULT length(n);
      DECLARE i TINYINT UNSIGNED DEFAULT l;
      DECLARE s SMALLINT UNSIGNED DEFAULT 0;
      WHILE i > 0 DO
        SET x = mid(n,i,1);
        IF (l-i) mod 2 = 0 THEN
          SET x = x * 2;
        END IF;
        SET s = s + x div 10 + x mod 10;
        SET i = i - 1;
      END WHILE;
      RETURN ceil(s/10)*10-s;
    END;
    

    然后可以在SQL查询中直接使用函数:

    mysql> SELECT ccc(1234567890123452);
    +-----------------------+
    | ccc(1234567890123452) |
    +-----------------------+
    |                     1 |
    +-----------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT ccc(1234567890123451);
    +-----------------------+
    | ccc(1234567890123451) |
    +-----------------------+
    |                     0 |
    +-----------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT ccd(123456789012345);
    +----------------------+
    | ccd(123456789012345) |
    +----------------------+
    |                    2 |
    +----------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT ccd(234567890123451);
    +----------------------+
    | ccd(234567890123451) |
    +----------------------+
    |                    1 |
    +----------------------+
    1 row in set (0.00 sec)
    
        8
  •  -1
  •   Chad Moran    16 年前

    这只是为了使用一些基本的正则表达式模式来确保数字是有效的。

    注意,这并不检查是否有人在使用这些数字。

    http://www.roscripts.com/How_to_validate_credit_card_numbers-106.html