Skip Menu |

This queue is for tickets about the Business-OnlinePayment-PayflowPro CPAN distribution.

Report information
The Basics
Id: 48696
Status: resolved
Priority: 0/
Queue: Business-OnlinePayment-PayflowPro

People
Owner: PLOBBES [...] cpan.org
Requestors: josh [...] infogears.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: 1.00



Subject: Use CGI::Util instead of CGI
Date: Fri, 14 Aug 2009 00:25:09 -0600
To: bug-Business-OnlinePayment-PayflowPro [...] rt.cpan.org
From: Josh Rosenbaum <josh [...] infogears.com>
This patch modifies Business::OnlinePayment::PayflowPro 0.07 to: *) utilize CGI::Util to parse the response instead of CGI. This reduces the memory footprint and overhead of using the entire CGI module. (We fallback to the old CGI method of unescaping if CGI::Util is unavailable, such as is the case in older Perls.) *) add a _get_response() routine which can be used to parse the response and get a hash of the values returned. This is useful if you need to get at a particular value in the returned response. *) For our particular case, we had some very old legacy code that defined its own CGI package as well, so that was getting trounced on by the "use CGI" here and this fixes that. Tests can be added if this patch is accepted. -- Josh Rosenbaum
--- PayflowPro.pm.orig 2009-08-13 18:11:50.000000000 -0600 +++ PayflowPro.pm.new 2009-08-13 18:27:19.000000000 -0600 @@ -3,16 +3,29 @@ use strict; use vars qw($VERSION $DEBUG); use Carp qw(carp croak); -use CGI; use Digest::MD5; use Business::OnlinePayment::HTTPS 0.06; use base qw(Business::OnlinePayment::HTTPS); -$VERSION = '0.07'; +$VERSION = '0.08'; $VERSION = eval $VERSION; $DEBUG = 0; +my $no_cgi_util; + +BEGIN { + eval { + + # CGI::Util was included starting with Perl 5.6. For previous Perls, we need + # to be sure to use the old simple CGI based method of unescaping + require CGI::Util; + }; + if ($@) { + $no_cgi_util = 1; + } +} + # return current request_id or generate a new one if not yet set sub request_id { my $self = shift; @@ -256,21 +269,21 @@ $self->response_headers( \%resp_headers ); # $page should contain name=value[[&name=value]...] pairs - my $cgi = CGI->new("$page"); + my $response = $self->_get_response( \$page ); # AVS and CVS values may be set on success or failure my $avs_code; - if ( defined $cgi->param("AVSADDR") or defined $cgi->param("AVSZIP") ) { - if ( $cgi->param("AVSADDR") eq "Y" && $cgi->param("AVSZIP") eq "Y" ) { + if ( defined $response->{"AVSADDR"} or defined $response->{"AVSZIP"} ) { + if ( $response->{"AVSADDR"} eq "Y" && $response->{"AVSZIP"} eq "Y" ) { $avs_code = "Y"; } - elsif ( $cgi->param("AVSADDR") eq "Y" ) { + elsif ( $response->{"AVSADDR"} eq "Y" ) { $avs_code = "A"; } - elsif ( $cgi->param("AVSZIP") eq "Y" ) { + elsif ( $response->{"AVSZIP"} eq "Y" ) { $avs_code = "Z"; } - elsif ( $cgi->param("AVSADDR") eq "N" or $cgi->param("AVSZIP") eq "N" ) + elsif ( $response->{"AVSADDR"} eq "N" or $response->{"AVSZIP"} eq "N" ) { $avs_code = "N"; } @@ -280,14 +293,14 @@ } $self->avs_code($avs_code); - $self->cvv2_response( $cgi->param("CVV2MATCH") ); - $self->result_code( $cgi->param("RESULT") ); - $self->order_number( $cgi->param("PNREF") ); - $self->error_message( $cgi->param("RESPMSG") ); - $self->authorization( $cgi->param("AUTHCODE") ); + $self->cvv2_response( $response->{"CVV2MATCH"} ); + $self->result_code( $response->{"RESULT"} ); + $self->order_number( $response->{"PNREF"} ); + $self->error_message( $response->{"RESPMSG"} ); + $self->authorization( $response->{"AUTHCODE"} ); # RESULT must be an explicit zero, not just numerically equal - if ( $cgi->param("RESULT") eq "0" ) { + if ( defined( $response->{"RESULT"} ) && $response->{"RESULT"} eq "0" ) { $self->is_success(1); } else { @@ -295,6 +308,38 @@ } } +# Make this a routine so that others can process the response page for params. +# Based on parse_params in CGI by Lincoln D. Stein. +sub _get_response { + my ( $self, $page ) = @_; + + my %response; + + if ( !defined($page) || ( ref($page) && !defined($$page) ) ) { + return \%response; + } + + my ( $param, $value ); + foreach ( split( /[&;]/, ref($page) ? $$page : $page ) ) { + ( $param, $value ) = split( '=', $_, 2 ); + next unless defined $param; + $value = '' unless defined $value; + + if ($no_cgi_util) { # use old pre-CGI::Util method of unescaping + $param =~ tr/+/ /; # pluses become spaces + $param =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge; + $value =~ tr/+/ /; # pluses become spaces + $value =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge; + } + else { + $param = CGI::Util::unescape($param); + $value = CGI::Util::unescape($value); + } + $response{$param} = $value; + } + return \%response; +} + 1; __END__
Josh, thanks for the patch and for the conversation/cooperation leading up to this! I'll work on incorporating that in the next release. I would love to get a test case or two added for this, so if you have a little time to put together one please feel free to email and/or attach to this bug.
Subject: Re: [rt.cpan.org #48696] Use CGI::Util instead of CGI
Date: Fri, 14 Aug 2009 12:38:40 -0600
To: bug-Business-OnlinePayment-PayflowPro [...] rt.cpan.org
From: Josh Rosenbaum <josh [...] infogears.com>
Phil Lobbes via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=48696 > > > Josh, thanks for the patch and for the conversation/cooperation leading > up to this! I'll work on incorporating that in the next release. I > would love to get a test case or two added for this, so if you have a > little time to put together one please feel free to email and/or attach > to this bug.
Hey Phil, Thanks for your time, conversation, and the module. :) Here is a diff for bop.t 0.07 to add 6 tests to verify _get_response() is working correctly. I ran tidy on my code before doing the diff. Let me know if you feel any changes are needed. Cheers, -- Josh Rosenbaum
--- bop.t.orig 2009-08-14 12:18:45.000000000 -0600 +++ bop.t.new 2009-08-14 12:24:10.000000000 -0600 @@ -2,7 +2,7 @@ use strict; use warnings; -use Test::More tests => 24; +use Test::More tests => 30; use Business::OnlinePayment; @@ -98,3 +98,43 @@ is( $obj->request_id($id), $id, "request_id() can be set" ); is( $obj->request_id, $id, "request_id() remains set" ); } + +{ # _get_response - response parsing + my $obj = $package->new($driver); + + is_deeply( + $obj->_get_response('%66%6F%78=%71%75%69%63%6B%20%25%26%3B&e=3+3'), + { fox => 'quick %&;', e => '3 3' }, + "_get_response 1 returns correct value" + ); + is_deeply( + $obj->_get_response('Foo=&&&&;;ab=t+t;q=2'), + { Foo => '', ab => 't t', q => '2' }, + "_get_response 2 returns correct value" + ); + is_deeply( + $obj->_get_response('f=s'), + { f => 's' }, + "_get_response 3 returns correct value" + ); + is_deeply( $obj->_get_response(''), + {}, "_get_response 4 returns correct value" ); + is_deeply( $obj->_get_response(undef), + {}, "_get_response 5 returns correct value" ); + is_deeply( + $obj->_get_response( +'RESULT=0&PNREF=QAAA1DF4B4F4&RESPMSG=Approved&AUTHCODE=111PNQ&AVSADDR=X&AVSZIP=X&CVV2MATCH=Y&IAVS=X' + ), + { + RESULT => '0', + PNREF => 'QAAA1DF4B4F4', + RESPMSG => 'Approved', + AUTHCODE => '111PNQ', + AVSADDR => 'X', + AVSZIP => 'X', + CVV2MATCH => 'Y', + IAVS => 'X' + }, + "_get_response 6 returns correct value" + ); +}
released v1.00 with fixes
released v1.00 with fixes