View Javadoc
1 /* 2 * $Header: /home/cvs/jakarta-commons/validator/src/share/org/apache/commons/validator/CreditCardValidator.java,v 1.16 2004/02/21 17:10:29 rleland Exp $ 3 * $Revision: 1.16 $ 4 * $Date: 2004/02/21 17:10:29 $ 5 * 6 * ==================================================================== 7 * Copyright 2001-2004 The Apache Software Foundation 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package org.apache.commons.validator; 23 24 import java.util.ArrayList; 25 import java.util.Collection; 26 import java.util.Iterator; 27 28 import org.apache.commons.validator.util.Flags; 29 30 /*** 31 * <p>Perform credit card validations.</p> 32 * <p> 33 * By default, all supported card types are allowed. You can specify which 34 * cards should pass validation by configuring the validation options. For 35 * example,<br/><code>CreditCardValidator ccv = new CreditCardValidator(CreditCardValidator.AMEX + CreditCardValidator.VISA);</code> 36 * configures the validator to only pass American Express and Visa cards. 37 * If a card type is not directly supported by this class, you can implement 38 * the CreditCardType interface and pass an instance into the 39 * <code>addAllowedCardType</code> method. 40 * </p> 41 * For a similar implementation in Perl, reference Sean M. Burke's 42 * <a href="http://www.speech.cs.cmu.edu/~sburke/pub/luhn_lib.html">script</a>. 43 * More information is also available 44 * <a href="http://www.merriampark.com/anatomycc.htm">here</a>. 45 * 46 * @since Validator 1.1 47 */ 48 public class CreditCardValidator { 49 50 /*** 51 * Option specifying that no cards are allowed. This is useful if 52 * you want only custom card types to validate so you turn off the 53 * default cards with this option. 54 * <br/> 55 * <pre> 56 * CreditCardValidator v = new CreditCardValidator(CreditCardValidator.NONE); 57 * v.addAllowedCardType(customType); 58 * v.isValid(aCardNumber); 59 * </pre> 60 * @since Validator 1.1.2 61 */ 62 public static final int NONE = 0; 63 64 /*** 65 * Option specifying that American Express cards are allowed. 66 */ 67 public static final int AMEX = 1 << 0; 68 69 /*** 70 * Option specifying that Visa cards are allowed. 71 */ 72 public static final int VISA = 1 << 1; 73 74 /*** 75 * Option specifying that Mastercard cards are allowed. 76 */ 77 public static final int MASTERCARD = 1 << 2; 78 79 /*** 80 * Option specifying that Discover cards are allowed. 81 */ 82 public static final int DISCOVER = 1 << 3; 83 84 /*** 85 * The CreditCardTypes that are allowed to pass validation. 86 */ 87 private Collection cardTypes = new ArrayList(); 88 89 /*** 90 * Create a new CreditCardValidator with default options. 91 */ 92 public CreditCardValidator() { 93 this(AMEX + VISA + MASTERCARD + DISCOVER); 94 } 95 96 /*** 97 * Create a new CreditCardValidator with the specified options. 98 * @param options Pass in 99 * CreditCardValidator.VISA + CreditCardValidator.AMEX to specify that 100 * those are the only valid card types. 101 */ 102 public CreditCardValidator(int options) { 103 super(); 104 105 Flags f = new Flags(options); 106 if (f.isOn(VISA)) { 107 this.cardTypes.add(new Visa()); 108 } 109 110 if (f.isOn(AMEX)) { 111 this.cardTypes.add(new Amex()); 112 } 113 114 if (f.isOn(MASTERCARD)) { 115 this.cardTypes.add(new Mastercard()); 116 } 117 118 if (f.isOn(DISCOVER)) { 119 this.cardTypes.add(new Discover()); 120 } 121 } 122 123 /*** 124 * Checks if the field is a valid credit card number. 125 * @param card The card number to validate. 126 */ 127 public boolean isValid(String card) { 128 if ((card == null) || (card.length() < 13) || (card.length() > 19)) { 129 return false; 130 } 131 132 if (!this.luhnCheck(card)) { 133 return false; 134 } 135 136 Iterator types = this.cardTypes.iterator(); 137 while (types.hasNext()) { 138 CreditCardType type = (CreditCardType) types.next(); 139 if (type.matches(card)) { 140 return true; 141 } 142 } 143 144 return false; 145 } 146 147 /*** 148 * Add an allowed CreditCardType that participates in the card 149 * validation algorithm. 150 * @param type The type that is now allowed to pass validation. 151 * @since Validator 1.1.2 152 */ 153 public void addAllowedCardType(CreditCardType type){ 154 this.cardTypes.add(type); 155 } 156 157 /*** 158 * Checks for a valid credit card number. 159 * @param cardNumber Credit Card Number. 160 */ 161 protected boolean luhnCheck(String cardNumber) { 162 // number must be validated as 0..9 numeric first!! 163 int digits = cardNumber.length(); 164 int oddOrEven = digits & 1; 165 long sum = 0; 166 for (int count = 0; count < digits; count++) { 167 int digit = 0; 168 try { 169 digit = Integer.parseInt(cardNumber.charAt(count) + ""); 170 } catch(NumberFormatException e) { 171 return false; 172 } 173 174 if (((count & 1) ^ oddOrEven) == 0) { // not 175 digit *= 2; 176 if (digit > 9) { 177 digit -= 9; 178 } 179 } 180 sum += digit; 181 } 182 183 return (sum == 0) ? false : (sum % 10 == 0); 184 } 185 186 /*** 187 * Checks for a valid credit card number. 188 * @param card Credit Card Number. 189 * @deprecated This will be removed in a future release. 190 */ 191 protected boolean isValidPrefix(String card) { 192 193 if (card.length() < 13) { 194 return false; 195 } 196 197 return new Visa().matches(card) 198 || new Amex().matches(card) 199 || new Mastercard().matches(card) 200 || new Discover().matches(card); 201 } 202 203 /*** 204 * CreditCardType implementations define how validation is performed 205 * for one type/brand of credit card. 206 * @since Validator 1.1.2 207 */ 208 public interface CreditCardType { 209 210 /*** 211 * Returns true if the card number matches this type of credit 212 * card. Note that this method is <strong>not</strong> responsible 213 * for analyzing the general form of the card number because 214 * <code>CreditCardValidator</code> performs those checks before 215 * calling this method. It is generally only required to valid the 216 * length and prefix of the number to determine if it's the correct 217 * type. 218 * @param card The card number, never null. 219 * @return true if the number matches. 220 */ 221 boolean matches(String card); 222 223 } 224 225 private class Visa implements CreditCardType { 226 private static final String PREFIX = "4"; 227 public boolean matches(String card) { 228 return ( 229 card.substring(0, 1).equals(PREFIX) 230 && (card.length() == 13 || card.length() == 16)); 231 } 232 } 233 234 private class Amex implements CreditCardType { 235 private static final String PREFIX = "34,37,"; 236 public boolean matches(String card) { 237 String prefix2 = card.substring(0, 2) + ","; 238 return ((PREFIX.indexOf(prefix2) != -1) && (card.length() == 15)); 239 } 240 } 241 242 private class Discover implements CreditCardType { 243 private static final String PREFIX = "6011"; 244 public boolean matches(String card) { 245 return (card.substring(0, 4).equals(PREFIX) && (card.length() == 16)); 246 } 247 } 248 249 private class Mastercard implements CreditCardType { 250 private static final String PREFIX = "51,52,53,54,55,"; 251 public boolean matches(String card) { 252 String prefix2 = card.substring(0, 2) + ","; 253 return ((PREFIX.indexOf(prefix2) != -1) && (card.length() == 16)); 254 } 255 } 256 257 }

This page was automatically generated by Maven