Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Re^2: How do you use Paypal IPN with Dancer2?

by $h4X4_|=73}{ (Monk)
on Jul 14, 2016 at 09:08 UTC ( [id://1167766]=note: print w/replies, xml ) Need Help??


in reply to Re: How do you use Paypal IPN with Dancer2?
in thread How do you use Paypal IPN with Dancer2?

I was going to mention Business::PayPal::IPN but i seen in Business::CPI::Gateway::PayPal::IPN the person that wrote it stated this about Business::PayPal::IPN = This is a rewrite of Business::PayPal::IPN. It works somewhat similar to it, and shares almost none of the same code.

Looking into what Business::PayPal::IPN does. It uses CGI to get the param's, so if the module works. that means it decodes the content before sending it back to PayPal.
You can try to use this code on $return_query to decode it and see if it works now.

sub decode_it { my $value = shift || ''; $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; return $value; }


Update: What perlfan means by "always return 200" is at the end of the code you need to print out a blank header like in the example. They use text/plain for the 200 response at the end. I'm not sure what that would equal in Dancer2 to get a header like that.
print "content-type: text/plain\n\n";

Replies are listed 'Best First'.
Re^3: How do you use Paypal IPN with Dancer2?
by perlfan (Vicar) on Jul 14, 2016 at 14:43 UTC
    Also, it has to be an HTTP status of 200. For example, if you have an uncaught die (but it's your fault not PPs) or your processing script crashes, then PP has no way of knowing not to repeat the IPN. Also, I'll have to take a look at Business::CPI::Gateway::PayPal::IPN. Thanks!

      You can catch the errors. This needs to be tested, but i bet it will work.

      #!/usr/bin/perl BEGIN { $| = 1; # if you need it use strict; use warnings; # Catch fatal errors. $SIG{__DIE__} = \&print_header; } #my $Just_Exit = 0; # It is highly recommended that you use version 6 upwards of # the UserAgent module since it provides for tighter server # certificate validation use LWP::UserAgent 6; my $query = ''; # read post from PayPal system and add 'cmd' # maybe add security to limit CONTENT_LENGTH read (STDIN, $query, $ENV{'CONTENT_LENGTH'}); $query = decode_it($query); $query .= '&cmd=_notify-validate'; # post back to PayPal system to validate my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 1 }); # https://www.paypal.com/cgi-bin/webscr # https://www.sandbox.paypal.com/cgi-bin/webscr my $req = HTTP::Request->new('POST', 'https://www.sandbox.paypal.com/c +gi-bin/webscr'); $req->content_type('application/x-www-form-urlencoded'); $req->header(Host => 'www.paypal.com'); # www.sandbox.paypal.com ? $req->content($query); my $res = $ua->request($req); # make the variable hash my %variable = map { split(m'='x, $_, 2) } grep { m'='x } split(m'&'x, $query); # assign posted variables to local variables my $item_name = $variable{'item_name'}; my $item_number = $variable{'item_number'}; my $payment_status = $variable{'payment_status'}; my $payment_amount = $variable{'mc_gross'}; my $payment_currency = $variable{'mc_currency'}; my $txn_id = $variable{'txn_id'}; my $receiver_email = $variable{'receiver_email'}; my $payer_email = $variable{'payer_email'}; if ($res->is_error) { # HTTP error } elsif ($res->content eq 'VERIFIED') { # check the $payment_status=Completed # check that $txn_id has not been previously processed # check that $receiver_email is your Primary PayPal email # check that $payment_amount/$payment_currency are correct # process payment } elsif ($res->content eq 'INVALID') { # log for manual investigation } else { # error } # end with header or will die with header print_header('Good'); sub print_header { my $error = shift || ''; # what you do here can die like logging. That can be detected with $Ju +st_Exit # so we know we have been here before and not to run the thing that di +ed # if ( $error ne 'Good' && ! $Just_Exit ) { # $Just_Exit = 1; # log($error); # } # error will be the die info with \n print "Content-type: text/plain\n\n"; exit(0); } sub decode_it { my $value = shift || ''; $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; return $value; }

Re^3: How do you use Paypal IPN with Dancer2?
by MorayJ (Beadle) on Jul 15, 2016 at 09:54 UTC

    Thanks, the decoding doesn't seem to be working if I've handled it correctly.

    As far as I can tell, I'm ending the script gracefully as the web page for sending the test reports everything ok (so I assume that means that it's got all the responses it expected)

    The 'invalid' it sends is in content not a header, incidentally.

    I do wonder if this issue may to be do with my apache set up and the forwarding to Dancer and if there might not be some kind of header changing going on there.

    I've also seen someone claim their script doesn't work in the simulator but does when they use the sandbox environment

    I think, for now, I'm going to use a different validation method - or just assume that the IPN is good enough as it is.

    If I solve this, I'll come back and report on it.

    Thanks again

    MorayJ

      Try using HTTP with the sandbox server.
      change https://www.sandbox.paypal.com/cgi-bin/webscr to http://www.sandbox.paypal.com/cgi-bin/webscr
      Update: and this my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 1 }); to this my $ua = LWP::UserAgent->new;
      That would mean your SSL encryption was not right or PP could have sent it to you none HTTPS or the sandbox server does not run SSL or...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1167766]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (4)
As of 2024-04-16 16:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found