Blog
printf and Octal Values
2009/08/13
We came across a strange issue while using ActiveMerchant to connect Moneris’ eSelect Plus payment gateway in one of our projects. ActiveMerchant raised an exception every time an order had ‘08’ or ‘09’ as the credit card expiry month.
The culprit was the way ActiveMerchant uses sprintf to format the month value before sending it to the payment gateway. In the file lib/active_merchant/billing/gateways/moneris.rb (around line 80):
def expdate(creditcard)
sprintf("%.4i", creditcard.year)[-2..-1] +
sprintf("%.2i", creditcard.month)
end
Let’s test that in irb.
>> sprintf("%.2i", '06')
=> "06"
>> sprintf("%.2i", '07')
=> "07"
>> sprintf("%.2i", '10')
=> "10"
>> sprintf("%.2i", '08')
ArgumentError: invalid value for Integer: "08"
from (irb):1:in `sprintf'
from (irb):1
from :0
>> sprintf("%.2i", '09')
ArgumentError: invalid value for Integer: "09"
from (irb):2:in `sprintf'
from (irb):2
from :0
Weird, isn’t it?
It seems like sprintf won’t accept values ‘08’ and ‘09’. This ruby-talk message explains why. The leading zero tell Ruby to interpret 8 and 9 as octal numbers. Anything above 7 is obviously not a valid octal number.
For example:
irb(main):005:0> 07 => 7 irb(main):006:0> 08 SyntaxError: compile error (irb):6: Illegal octal digit from (irb):6 from :0
The solution is quite simple: just make sure you cast the expiry month as an integer (using to_i) before creating an ActiveMerchant credit card object.