1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autofill/credit_card_field.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <stddef.h> 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/logging.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string16.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/string_util.h" 133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autofill/autofill_field.h" 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/autofill/field_types.h" 163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "grit/autofill_resources.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CreditCardField::GetFieldInfo(FieldTypeMap* field_type_map) const { 20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool ok = Add(field_type_map, number_, AutofillType(CREDIT_CARD_NUMBER)); 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ok); 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the heuristics detected first and last name in separate fields, 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // then ignore both fields. Putting them into separate fields is probably 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // wrong, because the credit card can also contain a middle name or middle 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // initial. 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (cardholder_last_ == NULL) { 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add() will check if cardholder_ is != NULL. 29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ok = ok && Add(field_type_map, cardholder_, AutofillType(CREDIT_CARD_NAME)); 303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ok); 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ok = ok && Add(field_type_map, type_, AutofillType(CREDIT_CARD_TYPE)); 343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(ok); 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ok = ok && Add(field_type_map, expiration_month_, 36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutofillType(CREDIT_CARD_EXP_MONTH)); 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ok); 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ok = ok && Add(field_type_map, expiration_year_, 39dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR)); 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ok); 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return ok; 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickFormFieldType CreditCardField::GetFormFieldType() const { 46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return kCreditCardType; 47731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 48731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCreditCardField* CreditCardField::Parse( 51dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::vector<AutofillField*>::const_iterator* iter, 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_ecml) { 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<CreditCardField> credit_card_field(new CreditCardField); 54dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::vector<AutofillField*>::const_iterator q = *iter; 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string16 pattern; 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Credit card fields can appear in many different orders. 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We loop until no more credit card related fields are found, see |break| at 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // bottom of the loop. 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int fields = 0; true; ++fields) { 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Sometimes the cardholder field is just labeled "name". Unfortunately this 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is a dangerously generic word to search for, since it will often match a 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // name (not cardholder name) field before or after credit card fields. So 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we search for "name" only when we've already parsed at least one other 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // credit card field and haven't yet parsed the expiration date (which 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // usually appears at the end). 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (credit_card_field->cardholder_ == NULL) { 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string16 name_pattern; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (is_ecml) { 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name_pattern = GetEcmlPattern(kEcmlCardHolder); 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (fields == 0 || credit_card_field->expiration_month_) { 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // at beginning or end 74d8e800e5cd4b5ff1c84124f27b98f9c174ec2738Ben Murdoch name_pattern = l10n_util::GetStringUTF16( 75d8e800e5cd4b5ff1c84124f27b98f9c174ec2738Ben Murdoch IDS_AUTOFILL_NAME_ON_CARD_RE); 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 77d8e800e5cd4b5ff1c84124f27b98f9c174ec2738Ben Murdoch name_pattern = l10n_util::GetStringUTF16( 78d8e800e5cd4b5ff1c84124f27b98f9c174ec2738Ben Murdoch IDS_AUTOFILL_NAME_ON_CARD_CONTEXTUAL_RE); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (ParseText(&q, name_pattern, &credit_card_field->cardholder_)) 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // As a hard-coded hack for Expedia's billing pages (expedia_checkout.html 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and ExpediaBilling.html in our test suite), recognize separate fields 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // for the cardholder's first and last name if they have the labels "cfnm" 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and "clnm". 89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::vector<AutofillField*>::const_iterator p = q; 90dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutofillField* first; 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!is_ecml && ParseText(&p, ASCIIToUTF16("^cfnm"), &first) && 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ParseText(&p, ASCIIToUTF16("^clnm"), 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &credit_card_field->cardholder_last_)) { 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch credit_card_field->cardholder_ = first; 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch q = p; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 100201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // We look for a card security code before we look for a credit 101201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // card number and match the general term "number". The security code 102201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // has a plethora of names; we've seen "verification #", 103201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // "verification number", "card identification number" and others listed 104201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // in the |pattern| below. 105201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (is_ecml) { 106201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch pattern = GetEcmlPattern(kEcmlCardVerification); 107201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } else { 108d8e800e5cd4b5ff1c84124f27b98f9c174ec2738Ben Murdoch pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_CVC_RE); 109201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } 110201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 111201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (credit_card_field->verification_ == NULL && 112201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch ParseText(&q, pattern, &credit_card_field->verification_)) 113201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch continue; 114201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(jhawkins): Parse the type select control. 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (is_ecml) 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pattern = GetEcmlPattern(kEcmlCardNumber); 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 120d8e800e5cd4b5ff1c84124f27b98f9c174ec2738Ben Murdoch pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_NUMBER_RE); 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (credit_card_field->number_ == NULL && ParseText(&q, pattern, 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &credit_card_field->number_)) 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if ((*q) && LowerCaseEqualsASCII((*q)->form_control_type, "month")) { 12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen credit_card_field->expiration_month_ = *q++; 12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // "Expiration date" is the most common label here, but some pages have 13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // "Expires", "exp. date" or "exp. month" and "exp. year". We also look 13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // for the field names ccmonth and ccyear, which appear on at least 4 of 13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // our test pages. 13372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 13472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // -> On at least one page (The China Shop2.html) we find only the labels 13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // "month" and "year". So for now we match these words directly; we'll 13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // see if this turns out to be too general. 13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Toolbar Bug 51451: indeed, simply matching "month" is too general for 13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // https://rps.fidelity.com/ftgw/rps/RtlCust/CreatePIN/Init. 14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Instead, we match only words beginning with "month". 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (is_ecml) 14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pattern = GetEcmlPattern(kEcmlCardExpireMonth); 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_MONTH_RE); 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if ((!credit_card_field->expiration_month_ || 14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen credit_card_field->expiration_month_->IsEmpty()) && 14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ParseText(&q, pattern, &credit_card_field->expiration_month_)) { 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (is_ecml) 15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pattern = GetEcmlPattern(kEcmlCardExpireYear); 15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen else 15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_DATE_RE); 15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!ParseText(&q, pattern, &credit_card_field->expiration_year_)) { 15672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return NULL; 15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen continue; 15972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ParseText(&q, GetEcmlPattern(kEcmlCardExpireDay))) 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Some pages (e.g. ExpediaBilling.html) have a "card description" 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // field; we parse this field but ignore it. 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We also ignore any other fields within a credit card block that 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // start with "card", under the assumption that they are related to 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the credit card section being processed but are uninteresting to us. 170d8e800e5cd4b5ff1c84124f27b98f9c174ec2738Ben Murdoch if (ParseText(&q, l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_IGNORED_RE))) 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 176731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Some pages have a billing address field after the cardholder name field. 177731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // For that case, allow only just the cardholder name field. The remaining 178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // CC fields will be picked up in a following CreditCardField. 179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (credit_card_field->cardholder_) { 180731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *iter = q; 181731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return credit_card_field.release(); 182731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 183731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // On some pages, the user selects a card type using radio buttons 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (e.g. test page Apple Store Billing.html). We can't handle that yet, 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so we treat the card type as optional for now. 187201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // The existence of a number or cvc in combination with expiration date is 188201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // a strong enough signal that this is a credit card. It is possible that 189201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // the number and name were parsed in a separate part of the form. So if 190201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // the cvc and date were found independently they are returned. 191201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if ((credit_card_field->number_ || credit_card_field->verification_) && 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch credit_card_field->expiration_month_ && 19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (credit_card_field->expiration_year_ || 19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (LowerCaseEqualsASCII( 195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen credit_card_field->expiration_month_->form_control_type, 19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "month")))) { 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *iter = q; 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return credit_card_field.release(); 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCreditCardField::CreditCardField() 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : cardholder_(NULL), 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cardholder_last_(NULL), 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_(NULL), 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch number_(NULL), 209201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch verification_(NULL), 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch expiration_month_(NULL), 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch expiration_year_(NULL) { 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 213