The current basic sanity check for card numbers (which is separate from the optional card validation routine) is broken. It uses intval($cc_data['cc_number']) == 0
, but this would pass, e.g., "3dsfklh". Payment gateways should not try to send non-numeric card numbers to merchant processing services, so there *should* be a sanity check like this, but it should check that every digit is a numeric with the ctype_digit()
PHP function. (The is_numeric function is inappropriate.)
N.B. Given that the credit card number validation routine currently doesn't work properly for Maestro cards (the identification of cards by their first digit is ambiguous), this sanity check is particularly helpful.
Comments
Comment #1
TR CreditAttribution: TR commentedStupid weakly-typed languages... Yes, that should be fixed.
But Ubercart wouldn't pass a non-numeric to the gateway, because it would fail the card number checksum calculation. The checksum is the important part (and is "on" by default), the other stuff is, as you say, a sanity check.
Comment #2
solarian CreditAttribution: solarian commentedUnfortunately the checksum doesn't seem to work with the test number for 18-digit Maestro cards given by my payment processing company, and having looked at the internal logic of the checksum, it doesn't handle card type identification properly. So this is just a sanity check for people (like me) who need to turn off the checksum feature.
Comment #3
TR CreditAttribution: TR commentedThere are several issues here, and it's not clear we're talking about the same thing.
When I say "checksum" I mean a checksum computed using all the digits of the card number, according to the Luhn algorithm. All the test card numbers on the page you reference above pass this test (I checked them just now).
This checksum is computed in the function _valid_card_number(). That function *also* does 2 other checks - the faulty is_numeric() check, and a check on the first digit of the card number. On examination, it seems that the first digit will fail for International Maestro if and only if you don't also accept American Express. That's a valid point, and should be fixed.
I'm in favor of *more* validation, not less, since catching bad card numbers up-front avoids service charges from payment gateways and helps prevent problems for those stores that are doing manual processing of credit card numbers.
Comment #4
solarian CreditAttribution: solarian commentedis_numeric() is *firstly* used in a test condition at the point where _valid_card_number() is called. I'm talking about that piece of code.
The _valid_card_number() function is broken too, I agree -- assuming all cards that start with '3' are Amex is one, and so is the use of is_numeric(), but it doesn't end there. One need only do some simple checking using Google to see that the same is true for those other tests based on the first digit of the card number. Clearly this function is in need of urgent review, since a lot of people shopping with Ubercart will find their cards rejected for no good reason. This is bad for merchants using Ubercart, and the default setting of this function should at least be 'off' for now.
I was not aware that payment gateways might charge for failed card transactions. Which companies do this?
Comment #5
rszrama CreditAttribution: rszrama commentedI'm going through and doing some housecleaning so we can put out a 1.1 release and wanted to follow up here.
I don't see any bugs associated with this issue but take from it that the sanity checking should be more specific for the optional validation and inclusive of other cards. I'm not too fond of the whole checkboxes approach to specifying valid card types anyways, as it's limited as has been pointed out here.
The code block in question in the original post was
EDIT: Ok, Lyle pointed out I was reading the original post wrong. When you're saying it would pass, you're saying it would == 3 and not that it would == 0. So, this would still fail a checksum but only if you have number validation turned on. I don't see any reason for it not to be turned on, so that's a good workaround.
I committed a change to ctype_digit() as recommended for the 1.1.
Comment #6
solarian CreditAttribution: solarian commentedUnfortunately the committed fix does not solve this problem in the manner I think it should.
This simply turns on full card validation if there are non-digits in the card number. OK, it will then reject it; but in doing so it violates the shop owner's configuration, and critically it will also reject other cards that do not pass the
_valid_card_number()
function. This function is specifically what I (and others) are trying to avoid (for reasons best addressed elsewhere). What I am proposing (and I thought I submitted a patch, but I can't see it now) is a separate sanity check, as follows:This will return FALSE if the user enters a card number that includes non-numeric characters; or, if card validation is turned on, it will apply that function.
Hope this makes it clear! The thing about == 0 or == 3 is just a nuisance in PHP -- I don't understand why a string like "5iuhggs" would cast to integer "5"...
Comment #7
rszrama CreditAttribution: rszrama commentedI see what ya mean. Made your change. Is this issue closed?
fwiw, most card types check out w/ the Luhn algorithm (there's a Wikipedia article on it), and when I tested the Maestro test number from Protx it worked fine.
Comment #8
solarian CreditAttribution: solarian commentedThanks for the commit.
Re: Maestro, not sure what's going on there -- indeed, UK Maestro does seem to work fine (and it does use the Luhn algorithm).
Comment #9
solarian CreditAttribution: solarian commentedBut International Maestro *doesn't* validate -- I think I must have been referring to that.
Comment #10
cYu CreditAttribution: cYu commentedBrianV came by #drupal-ubercart today wondering why Ubercart rejects card numbers with spaces in them. For example 4111 1111 1111 1111. He stated...
"has anyone else had an issue like this? I mean, the client gets several phone calls per day from various customers about this. I would think other people would have noticed this"
Do gateways generally accept this type of number and is Ubercart incorrectly filtering these out as invalid?
Comment #11
rszrama CreditAttribution: rszrama commentedafaik, any payment gateway I've worked with does not accept spaces. I imagine we could strip them out when we filter the input. I guess this was a non-issue before we updated the CC number field to be 19 characters long instead of the old 16.
Comment #12
cYu CreditAttribution: cYu commentedYeah, it would be nice if a string replace was added where the $_POST is processed into the $cc_data array in uc_payment_method_credit()
Comment #13
postcarbonjason CreditAttribution: postcarbonjason commentedRegarding the CC# being able to accept numbers with spaces, I just ran into this as well - due to a weird bug (http://www.ubercart.org/forum/bug_reports/8098/cc_number_format_validati...) where optional review checkout review was causing "invalid" card numbers with spaces in them to be submitted to Authorize.net in spite of being flagged as invalid by the checkout form, it appears that the CC#'s with spaces were properly accepted by Auth.net in my case...
I agree that it would be nice to collapse out the spaces in the CC# field, for usability sake.
Comment #14
rszrama CreditAttribution: rszrama commentedComment #15
rszrama CreditAttribution: rszrama commentedFunny how fixing one issue opens up others... never had this problem before upping the size of that textfield to 19 characters for Maestro cards. :P
Anyways, tweaked it to remove spaces and am closing this issue out.
Comment #17
vdsteph CreditAttribution: vdsteph commentedI am a beginner at PHP codes. Can I get assistance on how to validate a cc number? Here is what I have started and I know I am missing a function() but not sure how to write the code:
enctype="application/x-www-form-urlencoded">" />