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

Hi, thanks for looking

You're right to notice that I've got that the other way round - I have tried it as the original.

This is one of the reasons the script seems to be out of date as paypal docs now talk about prefixing rather than appending (though I have found one comment suggesting that either way now works). They even have an example showing the return content with it prefixed.

As far as I can tell it is prefixing fine. I'm wondering about encoding and stuff. It's almost certainly something ridiculous that I'm overlooking.

I'm going to investigate Dancer2's delayed, as might help to keep everything Dancer.

Thanks again

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

Replies are listed 'Best First'.
Re^3: How do you use Paypal IPN with Dancer2?
by $h4X4_|=73}{ (Monk) on Jul 12, 2016 at 18:16 UTC

    In the trouble shooting tips they say to keep the same encoding.
    Receiving an INVALID message from PayPal in response to your listener's post back for validation "Ensure that you use the same character encoding for your response string as the encoding specified in the charset field of the original IPN message. When testing using the IPN Simulator, the character encoding will always be UTF-8."

    Update: But I use PDT because "So, use PDT if your site includes a feature that requires immediate payment notification." IPN vs. PDT

    Update 2: From what I can remember of IPN. It does not matter that much that it comes back "INVALID" because all that is saying is that you did not return the data back the way PayPal wanted. But the transaction still will go through and you should still receive the transaction info from the first IPN response.

    Update 3: You did mention encoding and that made me think that maybe the content your getting from request->body; could be encoded or maybe decoded. Or LWP could encode the data before sending it making it a double encoded string. Just a few more things to check for.

      Update 2: From what I can remember of IPN. It does not matter that much that it comes back "INVALID" because all that is saying is that you did not return the data back the way PayPal wanted. But the transaction still will go through and you should still receive the transaction info from the first IPN response.

      I've temporarily moved on, but will be coming back to this...was a bit tired of tearning at my hair. Will report back here - but this is a really good point...I could probably live with an unvalidated for the time being as we're not talking about huge amount of sales attracting thousands of cheats

        It can work perfectly. I see a spot in your code that could return 'INVALID'

        $req->content("\n\n"); my $res = $ua->request($req); debug "First response: " $res; $req->content($return_query); $res = $ua->request($req); debug "Second response: " . Dumper $res;
        I think it should be like this.
        my $return_query = request->body; debug 'First response: ' request; # a way to see if you need to decode is check the param payment_date # if it has % and + its encoded. $return_query =~ tr/+/ /; $return_query =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $return_query = 'cmd=_notify-validate&' . $return_query; # post back to PayPal system to validate my $ua = LWP::UserAgent->new( ssl_opts => { verify_hostname => 1 } ); +#ssl_opts => { verify_hostname => 1 } my $req = HTTP::Request->new('POST', 'https://www.sandbox.paypal.com/c +gi-bin/webscr'); $req->content_type('application/x-www-form-urlencoded; charset=UTF- +8'); # maybe Host => 'www.sandbox.paypal.com' when using sandbox? $req->header(Host => 'www.paypal.com'); $req->content($return_query); my $res = $ua->request($req); debug "Second response: " . Dumper $res; # make the variable hash my %variable = map { split(m'='x, $_, 2) } grep { m'='x } split(m'&'x, $return_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) { debug "It's an error"; # HTTP error } elsif ($res->content eq 'VERIFIED') { debug "$payment_status"; # 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') { debug "It's invalid"; # log for manual investigation } else { debug "It's an error"; # error } print "Content-type: text/plain\n\n"; exit(0);
        This code still has the die issues that perlfan mentioned. I don't use Dancer2 to know how or if it handles die errors.