首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 通用信用卡驗證解決方案:四步驟驗證流程(The Analysis and Solutions Company 版本)

     編輯:PHP 綜合知識

背景

這是一個經典的信用卡驗證函式庫(版本 3.5,2000 年發布),採用四步驟驗證流程,支援 8 種主流卡別。雖年代久遠,但其邏輯架構清晰,適合學習驗證流程設計。

四步驟驗證流程

  1. 清理輸入:移除空格、非數字字元,限制長度 ≤ 19
  2. 前綴辨識:前 4 碼對照卡別範圍,決定卡別與預期長度
  3. 長度驗證:實際長度是否符合該卡別規定
  4. Luhn 校驗:Mod 10 演算法驗證校驗碼

核心程式碼(現代化重構)

<?php
class CreditCardValidator {
    private string $cardName = '';
    
    public function validate(string $number): bool {
        $number = $this->onlyNumeric($number);
        
        // Step 2: 前綴辨識
        if (!$this->identifyCardType($number)) return false;
        
        // Step 3: 長度驗證
        if (!$this->checkLength($number)) return false;
        
        // Step 4: Luhn 校驗
        return $this->mod10Check($number);
    }
    
    public function getCardName(): string {
        return $this->cardName;
    }
    
    private function onlyNumeric(string $number): string {
        return substr(preg_replace('/\D/', '', $number), 0, 19);
    }
    
    private function identifyCardType(string $number): bool {
        $prefix4 = (int)substr($number, 0, 4);
        $len = strlen($number);
        
        $rules = [
            // [minPrefix, maxPrefix, cardName, expectedLength]
            [3000, 3059, 'Diners Club', 14],
            [3600, 3699, 'Diners Club', 14],
            [3800, 3889, 'Diners Club', 14],
            [3400, 3499, 'American Express', 15],
            [3700, 3799, 'American Express', 15],
            [3528, 3589, 'JCB', 16],
            [3890, 3899, 'Carte Blanche', 14],
            [4000, 4999, 'Visa', null], // Visa 長度特殊處理
            [5100, 5599, 'MasterCard', 16],
            [5610, 5610, 'Australian BankCard', 16],
            [6011, 6011, 'Discover/Novus', 16],
        ];
        
        foreach ($rules as [$min, $max, $name, $expectedLen]) {
            if ($prefix4 >= $min && $prefix4 <= $max) {
                $this->cardName = $name;
                if ($name === 'Visa') {
                    $this->expectedLength = $len > 14 ? 16 : ($len < 14 ? 13 : -1);
                } else {
                    $this->expectedLength = $expectedLen;
                }
                return true;
            }
        }
        return false;
    }
    
    private int $expectedLength = 0;
    
    private function checkLength(string $number): bool {
        $len = strlen($number);
        if ($this->expectedLength === -1) return false; // Visa 14 碼無效
        if ($len !== $this->expectedLength) {
            $diff = $len - $this->expectedLength;
            // 可在這裡記錄錯誤訊息
            return false;
        }
        return true;
    }
    
    private function mod10Check(string $number): bool {
        $sum = 0;
        $len = strlen($number);
        $parity = $len % 2;
        
        for ($i = 0; $i < $len; $i++) {
            $digit = (int)$number[$i];
            if ($i % 2 === $parity) {
                $digit *= 2;
                if ($digit > 9) $digit -= 9;
            }
            $sum += $digit;
        }
        return $sum % 10 === 0;
    }
}

// 使用範例
$validator = new CreditCardValidator();
$cards = [
    '4532 0151 1283 0366',  // Visa
    '5555 5555 5555 4444',  // MasterCard
    '3782 822463 10005',    // Amex
    '6011 1111 1111 1117',  // Discover
    '1234 5678 9012 3456',  // Invalid
];

foreach ($cards as $card) {
    $valid = $validator->validate($card);
    echo "卡號:$card => " . ($valid ? "✅ {$validator->getCardName()}" : "❌ 無效") . "\n";
}
?>

原始版本與現代版本差異

特性原始版 (2000)現代重構
架構全域函數 + 全域變數類別封裝、單一職責
錯誤處理直接 echo HTML回傳布林/拋出例外
卡別範圍2000 年資料可擴充陣列配置
Visa 14 碼處理直接輸出錯誤 HTML回傳 false 由呼叫端處理
測試性難以單元測試易於 Mock 與測試

擴充:新增卡別(如 UnionPay、Maestro)

// 在 $rules 陣列新增
[6200, 6299, 'UnionPay', 16],      // UnionPay 62 開頭
[5018, 5018, 'Maestro', 12],       // Maestro 部分範圍
[5020, 5020, 'Maestro', 12],
[5038, 5038, 'Maestro', 12],
[6304, 6304, 'Maestro', 16],
[6759, 6759, 'Maestro', 16],
[6761, 6763, 'Maestro', 16],

結語

經典演算法邏輯不變,但程式架構需與時俱進。現代專案建議:

  • 使用成熟套件(如 `omnipay/common`、`stripe-php`)
  • 前端採用 Token 化,後端不接觸完整卡號
  • 若需自行驗證,封裝為可測試、可擴充的類別
  • 定期更新 BIN 資料庫(前 6-8 碼)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved