简体   繁体   中英

Validating credit cards using Stripe with iOS

I am starting to integrate Stripe to an iOS app I am making and I have got to a point where I need to validate the card information.

I tried:

#pragma mark - My Actions

- (IBAction)buyButtonTapped:(id)sender {

  //Populate STPCard property
  self.stripeCard = [[STPCard alloc]init];
  self.stripeCard.name = self.txtFieldCardHolderName.text;
  self.stripeCard.number = self.txtFieldCardNumber.text;
  self.stripeCard.cvc = self.txtFieldCardCvc.text;
  self.stripeCard.expMonth = [self.selectedMonth integerValue];
  self.stripeCard.expYear = [self.selectedYear integerValue];

  //Validate Customer info
  if ([self validateCustomerInfo]) {
    [self performStripeOperation];
  }

} 

-(BOOL)validateCustomerInfo{

  //Create Alert

  UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Please, try again!"
                                                                 message:@"Please, enter all required information."
                                                          preferredStyle:UIAlertControllerStyleAlert];

  UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK"
                                                   style:UIAlertActionStyleDefault
                                                 handler:^(UIAlertAction * _Nonnull action) {

                                                   //Add some action

                                                 }];

  //Add its action
  [alert addAction:action];


  //Validate text fields
  if (self.txtFieldCardHolderName.text == 0 || self.txtFieldCardNumber.text == 0 || self.txtFieldCardExpDate.text == 0 || self.txtFieldCardCvc.text == 0) {

    [self presentViewController:alert animated:true completion:nil];
    return NO;
  }

  //Validate card number, CVC, expMonth, expYear
  NSError *error = nil;

  [self.stripeCard validateCardReturningError:&error];

  //3
  if (error) {
    alert.message = [error localizedDescription];
    [self presentViewController:alert animated:true completion:nil];
    return NO;
  }

  return YES;

}

I checked a couple of other questions here on StackOverflow and everyone seems to use validateCardReturningError method, and it is deprecated for iOS9.

Xcode complains and ask me to use STPCardValidator instead.

Can anyone help me with one example of card validation using STPCardValidator?

I noticed I could use the following Class method as well:

[STPCardValidator validationStateForNumber:self.txtFieldCardNumber.text validatingCardBrand:true];

But I'm not sure how to use that inside my validateCustomerInfo method.

- (IBAction)buyButtonTapped:(id)sender{

    param = [[STPCardParams alloc]init];
    param.number = txt_cc_no.text;
    param.cvc = txt_cc_cvvno.text;
    param.expMonth =[self.selectedMonth integerValue];
    param.expYear = [self.selectedYear integerValue];


   if ([self validateCustomerInfo]) {
       [self performStripeOperation];
   }

}
- (BOOL)validateCustomerInfo {

    //2. Validate card number, CVC, expMonth, expYear
    [STPCardValidator validationStateForExpirationMonth:[self.selectedMonth stringValue]];
    [STPCardValidator validationStateForExpirationYear:[self.selectedYear stringValue] inMonth:[self.selectedMonth stringValue]];
    if ([txt_cc_type.text isEqualToString:@"visa"]) {
        [STPCardValidator validationStateForCVC:txt_cc_cvvno.text cardBrand:STPCardBrandVisa];
        [STPCardValidator validationStateForNumber:txt_cc_no.text validatingCardBrand:STPCardBrandVisa];
    }
    else if ([txt_cc_type.text isEqualToString:@"MasterCard"]){
        [STPCardValidator validationStateForCVC:txt_cc_cvvno.text cardBrand:STPCardBrandMasterCard];
        [STPCardValidator validationStateForNumber:txt_cc_no.text validatingCardBrand:STPCardBrandMasterCard];
    }
    else if ([txt_cc_type.text isEqualToString:@"American Express"]){

        [STPCardValidator validationStateForCVC:txt_cc_cvvno.text cardBrand:STPCardBrandAmex];
        [STPCardValidator validationStateForNumber:txt_cc_no.text validatingCardBrand:STPCardBrandAmex];
    }
    else if ([txt_cc_type.text isEqualToString:@"Discover"]){
        [STPCardValidator validationStateForCVC:txt_cc_cvvno.text cardBrand:STPCardBrandDiscover];
        [STPCardValidator validationStateForNumber:txt_cc_no.text validatingCardBrand:STPCardBrandDiscover];
    }
    else if ([txt_cc_type.text isEqualToString:@"Diners Club"]){
        [STPCardValidator validationStateForCVC:txt_cc_cvvno.text cardBrand:STPCardBrandDinersClub];
        [STPCardValidator validationStateForNumber:txt_cc_no.text validatingCardBrand:STPCardBrandDinersClub];
    }
    else if ([txt_cc_type.text isEqualToString:@"JCB"]){
        [STPCardValidator validationStateForCVC:txt_cc_cvvno.text cardBrand:STPCardBrandJCB];
        [STPCardValidator validationStateForNumber:txt_cc_no.text validatingCardBrand:STPCardBrandJCB];
    }
    else if ([txt_cc_type.text isEqualToString:@"Unknown"]){
        [STPCardValidator validationStateForCVC:txt_cc_cvvno.text cardBrand:STPCardBrandUnknown];
        [STPCardValidator validationStateForNumber:txt_cc_no.text validatingCardBrand:STPCardBrandUnknown];
    }


    return YES;
}
- (void)performStripeOperation {
    [[STPAPIClient sharedClient] createTokenWithCard:param
                                          completion:^(STPToken *token, NSError *error) {
                                              if (error) {
                                                  //                                           [self handleError:error];
                                                  NSLog(@"ERRRRR = %@",error);
                                                  UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Please try again"
                                                                                                   message:[NSString stringWithFormat:@"%@",error.localizedDescription]
                                                                                                  delegate:nil
                                                                                         cancelButtonTitle:@"OK"
                                                                                         otherButtonTitles:nil];
                                                  [alert show];
                                              } else {

                                                 //when credit card details is correct code here
                                              }
                                          }];
}

Swift 5.0+

Don't forget to import Stripe

func isCardDetailValid(cardNumber : String, month : UInt, year : UInt, cvv : String) -> Bool {
    let params = STPCardParams()
    params.number = cardNumber
    params.expMonth = month
    params.expYear = year
    params.cvc = cvv
    if STPCardValidator.validationState(forCard: params) == .valid {
        return true
    } else {
        return false
    }
}

Swift 2.1 Version of Femina's answer. Note: validateCardType() is a regex function, if you want that too you can find it here How do you detect Credit card type based on number?

func validateCustomerInfo() -> Bool {
    // Validate card number, CVC, expMonth, expYear
    STPCardValidator.validationStateForExpirationMonth(self.expMonth.text!)
    STPCardValidator.validationStateForExpirationYear(self.expYear.text!, inMonth: self.expMonth.text!)

    if (self.validateCardType(creditCardField.text!) == "Visa") {
        STPCardValidator.validationStateForCVC(self.securityField.text!, cardBrand: STPCardBrand.Visa)
        STPCardValidator.validationStateForNumber(self.creditCardField.text!, validatingCardBrand: true)
    }
    else if (self.validateCardType(creditCardField.text!) == "MasterCard") {
        STPCardValidator.validationStateForCVC(self.securityField.text!, cardBrand: STPCardBrand.MasterCard)
        STPCardValidator.validationStateForNumber(self.creditCardField.text!, validatingCardBrand: true)
    }
    else if (self.validateCardType(creditCardField.text!) == "American Express") {
        STPCardValidator.validationStateForCVC(self.securityField.text!, cardBrand: STPCardBrand.Amex)
        STPCardValidator.validationStateForNumber(self.creditCardField.text!, validatingCardBrand: true)
    }
    else if (self.validateCardType(creditCardField.text!) == "Discover") {
        STPCardValidator.validationStateForCVC(self.securityField.text!, cardBrand: STPCardBrand.Discover)
        STPCardValidator.validationStateForNumber(self.creditCardField.text!, validatingCardBrand: true)
    }
    else if (self.validateCardType(creditCardField.text!) == "Diners Club") {
        STPCardValidator.validationStateForCVC(self.securityField.text!, cardBrand: STPCardBrand.DinersClub)
        STPCardValidator.validationStateForNumber(self.creditCardField.text!, validatingCardBrand: true)
    }
    else if (self.validateCardType(creditCardField.text!) == "JCB") {
        STPCardValidator.validationStateForCVC(self.securityField.text!, cardBrand: STPCardBrand.JCB)
        STPCardValidator.validationStateForNumber(self.creditCardField.text!, validatingCardBrand: true)
    }
    else if (self.validateCardType(creditCardField.text!) == "Unknown") {
        STPCardValidator.validationStateForCVC(self.securityField.text!, cardBrand: STPCardBrand.Unknown)
        STPCardValidator.validationStateForNumber(self.creditCardField.text!, validatingCardBrand: true)
    }

    return true
}

The simplest way of doing this instead of doing all the calculations.

You could use the validationStateForCard method of STPCardValidator which takes STPCardParams instance as an argument.

- (IBAction)buyButtonTapped:(id)sender{

    param = [[STPCardParams alloc]init];
    param.number = txt_cc_no.text;
    param.cvc = txt_cc_cvvno.text;
    param.expMonth =[self.selectedMonth integerValue];
    param.expYear = [self.selectedYear integerValue];


   if ([self validateCustomerInfo]) {
       [self performStripeOperation];
   }

}

func validateCustomerInfo() -> Bool {

    // Validate card number, CVC, expMonth, expYear
    return STPCardValidator.validationStateForCard(param) == .Valid
}

For swift 3

    // Validate all params at once
    let cardSate = STPCardValidator.validationState(forCard: cardParams)
    // Validate card number, CVC, expMonth, expYear one by one
    let numberState = STPCardValidator.validationState(forNumber: cardParams.number, validatingCardBrand: true)
    let cvcState = STPCardValidator.validationState(forCVC: cardParams.cvc ?? "", cardBrand: STPCardValidator.brand(forNumber: cardParams.number ?? ""))
    let expMonthState = STPCardValidator.validationState(forExpirationMonth: String(cardParams.expMonth ?? 0))
    let expYearState = STPCardValidator.validationState(forExpirationYear: String(cardParams.expYear ?? 0), inMonth: String(cardParams.expMonth ?? 0))

It's the complete and more proper Swift answer of @iOSArchitect.com

func paymentCardTextFieldDidChange(_ textField: STPPaymentCardTextField) {
    let isValid = isValidCard(cardNumber: textField.cardNumber, month: textField.expirationMonth, year: textField.expirationYear, cvv: textField.cvc)
}

func isValidCard(cardNumber: String?, month: UInt, year: UInt, cvv: String?) -> Bool {
    let params = STPCardParams()
    params.number = cardNumber
    params.expMonth = month
    params.expYear = year
    params.cvc = cvv
    if STPCardValidator.validationState(forCard: params) == .valid {
        return true
    } else {
        return false
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM