All pastes #241537 Raw Edit

Kiryn

public text v1 · immutable
·published 2006-11-06 08:50 UTC
rendered paste body
using System;
using System.Collections;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;
using System.Web.UI;

namespace FrostCommerce.Components
{
    /// <summary>
    /// Performs validation of the credit card number on checkout.
    /// </summary>
    public class CreditCardValidator : BaseValidator
    {
        /// <summary>
        /// Credit card type.
        /// </summary>
        private CardType _cardType;
        /// <summary>
        /// Credit card textbox
        /// </summary>
        private TextBox _creditBox;
        /// <summary>
        /// If we should check to test for length.
        /// </summary>
        private bool _valid;

        /// <summary>
        /// Default constructor
        /// </summary>
        public CreditCardValidator()
        {
            _valid = true;
            _cardType = CardType.All | CardType.Unknown;
        }

        protected override bool ControlPropertiesValid()
        {
            Control ctrl = FindControl(ControlToValidate);

            if (ctrl != null)
            {
                if (ctrl is TextBox)
                {
                    _creditBox = (TextBox)ctrl;
                    return (null != _creditBox);
                }
                else
                    return false;
            }
            else
                return false;
        }

        protected override bool EvaluateIsValid()
        {
            if (_valid)
            {
                if (IsValidCard(_creditBox.Text))
                {
                    return ValidCardNumber(_creditBox.Text);
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return ValidCardNumber(_creditBox.Text);
            }
        }

        /// <summary>
        /// Will ensure that the card is a valid length for the card type. If the
        /// card type isn't recognised it will return true by default.
        /// 
        /// The CreditCardValidator control also includes a CardTypes property that determines
        /// what card types should be accepted. If the card isn't recognised, and the Unknown card
        /// type is in the AcceptedCardTypes property then the DefaultLengthTest value will be
        /// returned.
        /// </summary>
        /// <param name="CardNumber">Credit card number to check.</param>
        /// <returns>
        /// Wither the card is of valid length and of credit number for
        /// the type of card.
        /// </returns>
        public bool IsValidCard(string CardNumber)
        {
            // AMEX
            if((Regex.IsMatch(CardNumber, "^(34|37)")) && ((_cardType & CardType.Amex) != 0))
                return ( 15 == CardNumber.Length);
            // MasterCard
            else if((Regex.IsMatch(CardNumber, "^(51|52|53|54|55)")) && ((_cardType & CardType.MasterCard) != 0))
                return ( 16 == CardNumber.Length);
            // Visa
            else if((Regex.IsMatch(CardNumber, "^(4)")) && ((_cardType & CardType.Visa) != 0))
                return ( 13 == CardNumber.Length || 16 == CardNumber.Length);
            // Diner's Card
            else if((Regex.IsMatch(CardNumber, "^(300|301|302|303|304|305|36|38)")) && ((_cardType & CardType.DinersClub) != 0))
                return ( 14 == CardNumber.Length);
            // Discover
            else if((Regex.IsMatch(CardNumber, "^(6011)")) && ((_cardType & CardType.Discover) != 0))
                return ( 16 == CardNumber.Length);
            // Unknown
            else
            {
                if((_cardType & CardType.Unknown) != 0)
                    return true;
                else
                    return false;
            }
        }

        /// <summary>
        /// Performs a validation of the credit card number using the Luhn's Formula.
        /// </summary>
        /// <param name="CardNumber">Credit Card number to validate.</param>
        /// <returns>
        /// Return wither its valid or not.
        /// </returns>
        private static bool ValidCardNumber(string CardNumber)
        {
            try
            {
                // Contain the numbers
                ArrayList Numbers = new ArrayList();
                // Length of the credit card
                int CardLength = CardNumber.Length;

                // Double the value of the alternate digits, starting with the second digit from
                // the right and for to the left
                // Now loop starting from the end
                for(int i = CardLength - 2; i >= 0; i = i - 2)
                {
                    // Now read the contents at each index
                    Numbers.Add(Int32.Parse(CardNumber[i].ToString()) * 2);
                }
                // Will hold the value of the Credit card
                int CheckSum = 0;

                // Add the seperate digits of all the products
                for(int count = 0; count <= Numbers.Count - 1; count++)
                {
                    // Holds the sum of the digits
                    int holdNumbers = 0;

                    // Check if the current number has more than one digit
                    if((int)Numbers[count] > 9)
                    {
                        
                        int numberLength = ((int) Numbers[count]).ToString().Length;

                        // Add the count to each digit
                        for(int i = 0; i < numberLength; i++)
                        {
                            holdNumbers = holdNumbers + Int32.Parse(((int)Numbers[count]).ToString()[i].ToString());
                        }
                    }
                    else
                    {
                        // Single digit add it to itself
                        holdNumbers = (int)Numbers[count];
                    }

                    // Add the num to the total
                    CheckSum = CheckSum + holdNumbers;
                }

                // Add all the digits that wasn't double from the right but
                // start from the most right number with alternating digits
                int origSum = 0;
                for(int i = CardLength - 1; i >= 0; i = i -2)
                {
                    origSum = origSum + Int32.Parse(CardNumber[i].ToString());
                }
                // Perform the final sum, if the sum modulus results in 0 then its validate else its a fake number
                return (((origSum + CheckSum) % 10) == 0);
            }
            catch(Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Should we validate the length of the credit cards?
        /// </summary>
        public bool ValidateCardType
        {
            get { return _valid; }
            set { _valid = value; }
        }

        /// <summary>
        /// String of all the credit cards we accept
        /// </summary>
        public string AcceptedCardTypes
        {
            get { return _cardType.ToString(); }
            set
            {
                _cardType = (CardType)Enum.Parse(typeof(CardType), value, false);
            }
        }
    }
}