Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

PayPal IPN return POST problem

Status
Not open for further replies.

MrCBofBCinTX

Technical User
Dec 24, 2003
164
US
I am trying to get paypal IPN script to work.
PayPal sends me a a list of variables an a normal POST.
I then send that back to PayPal.
All is good so far.

If everything is OK, PayPal than sends me back a POST that contains nothing at all except VERIFIED.

This is a page that is text.html and the content and source is VERIFIED, nothing else.

The post URL requested contains no information.

How do I obtain this content?
 
Are you using Paypal's validation script or one of your own?
Code:
#!/usr/bin/perl

# read post from PayPal system and add 'cmd'
read (STDIN, $query, $ENV{'CONTENT_LENGTH'});
$query .= '&cmd=_notify-validate';

# post back to PayPal system to validate
use LWP::UserAgent;
$ua = new LWP::UserAgent;
$req = new HTTP::Request 'POST','[URL unfurl="true"]https://www.paypal.com/cgi-bin/webscr';[/URL]
# note: if you have SSL encryption Enabled, use <[URL unfurl="true"]https://www.paypal.com/cgi-bin/webscr>[/URL] above
$req->content_type('application/x-[URL unfurl="true"]www-form-urlencoded');[/URL]
$req->content($query);
$res = $ua->request($req);

# split posted variables into pairs
@pairs = split(/&/, $query);
$count = 0;
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$variable{$name} = $value;
$count++;
}

# assign posted variables to local variables
# note: additional IPN variables also available -- see IPN documentation
$item_name = $variable{'item_name'};
$receiver_email = $variable{'receiver_email'};
$item_number = $variable{'item_number'};
$invoice = $variable{'invoice'};
$a = $variable{'custom'};
$payment_status = $variable{'payment_status'};
$payment_gross = $variable{'payment_gross'};
$txn_id = $variable{'txn_id'};
$payer_email = $variable{'payer_email'};
$amount = $variable{'amount'};
$on0 = $variable{'option_name1'};
$os0 = $variable{'option_selection1'};
$status = $res->content;
$note = $variable{'memo'};


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 an email address in your PayPal account
# process payment
# print to screen the following if the IPN POST was VERIFIED


print "content-type: text/plain\n\nOK\n";
print "<html><head><title>IPN Screendump</title></head>\n";
print "<body>your email address is <b>$payer_email</b>\n";
print "<br>you paid <b>$payment_gross</b>\n";
print "<br>you paid for <b>$item_number</b>\n";
print "<br>the color of your order was <b>$os0</b>\n";
print "<br>the value of custom was <b>$a</b>\n";
print "<br>the status was<b>$status</b>\n";
print "<br>the note said <b>$note</b>\n";
print "<br>the transaction id was <b>$txn_id</b>\n";
print "<br>the payment status was<b>$payment_status</b>\n";
print "</body></html>\n";


}
elsif ($res->content eq 'INVALID') {
# log for manual investigation
# print to screen the following if the IPN POST was INVALID

print "content-type: text/plain\n\nOK\n";

print "<html><head><title>IPN Screendump</title></head>\n";
print "<br>the status was<b>$status</b>\n";
print "</body></html>\n";


}
else {
# error
}

Keith
 
I use mod_perl. Is there a way to get a POSTs content without a list of params?
I haven't used plain CGI for a long time.
Seems like there must be a mod_perl way, but I can't find anything searching for it.
Other than this one hurdle, everything is working fine.
 
Not familiar with mod_perl so I really don't know what to suggest.
To be honest, I don't even know the difference between mod-perl and the perl I use.
I don't know why they insist on using the $ENV string rather than the CGI module but I am sure the decisions are made by minds far superior to mine.
I have used that script, well a far more embelished version, quite a lot and found it to be very reliable.

Keith
 
I wanted to reply back to make known how I solved this IPN situation.

I had no trouble at all with the mod_perl. Everything went as it should, but PayPal states that the params must be returned in the same order.
That isn't true.
They also say that &cmd=_notify-validate must be added to the end.
That isn't exactly true. Everything works ok at either end or even both ends.

[red]The real problem I had is that PayPal must receive back a 200 reply from my server before the transaction is complete.
There is no mention of this need in any of the documentation.[/red]

I admit that the example script shows a page returned to PayPal, but the example page does not look like something necessary. IMHO, it looks like something that would be sent to me during my own local testing!

After days of failure with my script (which always worked fine on my end to get verified response), I saw someone mention that PayPal needed to get a 200 for the process to complete.
[red]I added sending back a blank page header. Voila! All is fine now.[/red]

I hope search engines catch this. Even better, that PayPal would add a comment on their sample scripts!
I looked at many forums which lacked this simple answer.
 
Is that right, Mod_Perl you have to handroll your own handling of the querystring?

eg.
Code:
getFormData(\%frmFlds);

sub getFormData {
    my($hashRef) = shift;
    my($buffer) = "";

    if ($ENV{'REQUEST_METHOD'} eq 'GET') {
        $buffer = $ENV{'QUERY_STRING'};
    }
    else {
        read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
    }

    foreach (split(/&/, $buffer)) {
        my($key, $value) = split(/=/, $_);
        $key   = decodeURL($key);
        $value = decodeURL($value);
        %{$hashRef}->{$key} = $value;
    }
}

sub decodeURL {
    $_ = shift;
    tr/+/ /;
    s/%(..)/pack('c', hex($1))/eg;
    return($_);
}
I used to use this type of processing, but when I joined TT many moons ago, I was told to cease and desist immediately, it is very dangerous and bad practice and I should start using CGI for handling POST/GET data, and have done for many years now.

Why wouldn't you use the same logic when dealing with MOD_PERL ?



"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

MIME::Lite TLS Email Encryption - Perl v0.02 beta
 
Yes, you have to roll your own but Apache::Request does the same type of work that CGI.pm does but much faster and adds many options not available in CGI.pm.

Not hard at all.

You can run regular CGI with mod_perl, but after you learn how use mod_perl, you never want to again.
Mod_perl basically requires "perfect" programming styles, but that is always a good thing!
Like comments. I used to skip that but then I had to do maintenance and changes in my old code. Yuck. Now I comment everything wierd in my code.
 
Ok, thanks for the info.

I assume though Apache::Request doesn't decode STDIN $ENV{} like CGI does, otherwise you wouldn't need to roll your own.

Maybe one day I'll get into MOD_PERL only thing is it only works on *nix, and my day job is Windows / IIS with ActiveState perl, so no path for gaining MOD_PERL experience or training :-(

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

MIME::Lite TLS Email Encryption - Perl v0.02 beta
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top