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 bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

PayPal IPN Code using LWP 1

Status
Not open for further replies.

1DMF

Programmer
Jan 18, 2005
8,795
GB
Hello,

I'm attempting to set up the facility to enable people to purchase downloads from my site, I have found this may be possible with my PayPAl account using IPN (Instant Payment Notification).

However when clicking there link to supply me with example PERL code I was shown this
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"]http://www.paypal.com/cgi-bin/webscr';[/URL]
$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
$item_name = $variable{'item_name'};
$item_number = $variable{'item_number'};
$payment_status = $variable{'payment_status'};
$payment_amount = $variable{'mc_gross'};
$payment_currency = $variable{'mc_currency'};
$txn_id = $variable{'txn_id'};
$receiver_email = $variable{'receiver_email'};
$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
}
print "content-type: text/plain\n\n";
Now I'm no PERL expert as you all know but even to me this looks like invalid (non-compliant) code. where is the 'use strict', where are the variable definitions (our,my etc..) the STDIN is being arbitarily read without passing it through CGI or validation, surely this cant be right.

Any chance someone can help me re-write this correctly, will passing it through CGI to get value pairs effect the way this works?

All help is appreciated, as I don't want to plough ahead until i'm sure I have valid and strong paypal PERL code.

Regards
1DMF



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

I haven't tested this but it's a lot more strict-compliant than the original code.

Code:
#!/usr/bin/perl -w

use strict;
use warnings;
use CGI;
use URI::Escape;
use LWP::UserAgent;
use HTTP::Request;

# Create a CGI object
our $cgi = new CGI();

# Get all the variables from the form.
my @vars = ();
my %variables = ();
my $count = 0;
foreach my $what ($cgi->param) {
	$count++;
	my $is = $cgi->param ($what);
	push (@vars, "$what=$is");

	# URI decode this for our own use
	$is = uri_unescape ($is);
	$variables{$what} = $is;
}

# Create a scalar query string from the vars.
my $query = join ('&', @vars);

# Post back to the PayPal system.
my $ua = new LWP::UserAgent;
my $req = new HTTP::Request ('POST', '[URL unfurl="true"]http://www.paypal.com/cgi-bin/webscr');[/URL]
$req->content_type ('application/x-[URL unfurl="true"]www-form-urlencoded');[/URL]
$req->content ($query);
my $res = $ua->request ($req);

# Assign posted vars to local ones.
my $item_name        = $variable{item_name};
my $item_number      = $variable{item_number};
my $payment_status   = $variable{payment_status};
my $payment_amount   = $variable{payment_amount};
my $payment_currency = $variable{payment_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') {
	# verified
}
elsif ($res->content eq 'INVALID') {
	# log for manual investigation
}
else {
	# error
}

print "Content-Type: text/plain\n\n";
 
wow - thanks, i didn't expect someone to actually write the whole code for me, I was really looking for advice and another opinion on the matter.

You're a gent

[cheers]
1DMF

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you.
 
I've been playing with the code and decided I don't need IPN , what I need is PDT, the code they supply is below and it even seems to be "strict" compliant!
Code:
#!/usr/bin/perl -w


###

#

# PayPal PDT (Payment Data Transfer) CGI

#

###


use strict;

use CGI qw(:all unescape);

use CGI::Carp qw(fatalsToBrowser);


# These modules are required to make the secure HTTP request to PayPal.

use LWP::UserAgent;

use Crypt::SSLeay;


###

# CUSTOMIZE THIS: This is the seller's Payment Data Transfer authorization token.

#                  Replace this with the PDT token in "Website Payment Preferences"

under your account.

###


my $auth_token = "VUDGCF2EA5huqlEqbSLPbg0JY3F-Pokyf-99r2sZWPR4x7GkWZEa-zIG49O";


sub done_text {

    return (p('Your transaction has been completed, and a receipt for your purchase has been
emailed to you. You may log into your account at <a
href="[URL unfurl="true"]https://www.paypal.com/">www.paypal.com</a>[/URL] to view details of this transaction.'),
end_html());

}


print header(), start_html("Thank you for your purchase!");


# Set up the secure request to the PayPal server to fetch the transaction info

my $paypal_server = "[URL unfurl="true"]www.paypal.com";[/URL]


my $transaction = param("tx");


if (not $transaction) {

    print (h2("The transaction ID was not found."), done_text());


    exit();

}


my $paypal_url = "[URL unfurl="true"]https://$paypal_server/cgi-bin/webscr";[/URL]

my $query = join("&", "cmd=_notify-synch", "tx=$transaction", "at=$auth_token");


my $user_agent = new LWP::UserAgent;

my $request = new HTTP::Request("POST", $paypal_url);


$request->content_type("application/x-[URL unfurl="true"]www-form-urlencoded");[/URL]

$request->content($query);

# Make the request


my $result = $user_agent->request($request);


if ($result->is_error) {

    print(h1("An error was encountered"), br(), p("An error was encountered contacting the PayPal
server:"),

        $result->error_as_HTML, done_text());

    exit();

}


# Decode the response into individual lines and unescape any HTML escapes

my @response = split("\n", unescape($result->content));


# The status is always the first line of the response.

my $status = shift @response;


if ($status eq "SUCCESS") {

    # success

    my %transaction;


    foreach my $response_line (@response) {

      my ($key, $value) = split "=", $response_line;

      $transaction{$key} = $value;

    }

    # These are only some of the transaction details available; there are others.

    # You should print all the transaction details appropriate.

    print(h2("Here are the details of your purchase:"),

      ul(li("Customer Name: " . $transaction{'first_name'} . " " . $transaction{'last_name'}),

          li("Item: " . $transaction{'item_name'}),

          li("Amount: " . $transaction{'payment_gross'})));


} elsif ($status eq "FAIL") {

    print(h2("Unable to retrieve transaction details."));

    # failure

} else {

    # unknown error

    print(h2("Error retrieving transaction details."));

}


print done_text();
I'll post back how I get on :)

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

Part and Inventory Search

Sponsor

Back
Top