|
|
|
Rank: Starting Member
Groups: Registered
Joined: 7/19/2004 Posts: 1 Location: ,
|
Hi,
I've recently been working on a site that requires online payments but I needed the payment to have a callback (ipn) so I could update my database and send a personalised email to my customer if the payment was succesful. So I found paypal's ipn, it does everything I want it to do....one problem; the documentation is so poorly written I was confused after reading 'how ipn works'
I then found this site and noticed that neally everyone has the same issues I do; why do you have return_url & notify_url? can you use them together...if I use just return_url and have variables posted is it safe? etc...
I copied paypal's perl sample script (as everyone here probably did) and it still didn't make much sense...so, I used their script and modified it so most of your questions should be answered in the script.
BTW, you only need to use notify_url and NOT return_url...why?, well the script not only does the processing it also displays the results of the payment(no need for 2 scripts)
You can modify, improve the script any way you want:
Criticism welcome
#!/usr/bin/perl
#####################################
# CONFIG - JUST NEATER IF ITS HERE #
#####################################
$paypal_email = 'me@mydomain.com'; # THIS SHOULD BE THE EMAIL ADDRESS YOU SIGNED UP WITH PAYPAL
# THIS IS USED TO CHECK THAT THE FUNDS HAVE BEEN PAID TO YOU AND NOT SOMEONE ELSE TRYING TO RIP YOU OFF
# READ DATA POSTED FROM PAYPAL
read (STDIN, $query, $ENV{'CONTENT_LENGTH'});
$query .= '&cmd=_notify-validate';
# SEND DATA BACK TO PAYPAL TO VALIDATE THE PAYMENT
use LWP::UserAgent;
$ua = new LWP::UserAgent;
$req = new HTTP::Request 'POST','http://www.paypal.com/cgi-bin/webscr'';
$req->content_type('application/x-www-form-urlencoded');
$req->content($query);
$res = $ua->request($req);
# GET POSTED DATA FROM PAYPAL
%form = &parse;
# VARIABLES SENT FROM PAYPAL ABOUT THE PAYMENT TO YOU
$receiver_email = $form{'receiver_email'};
$item_name = $form{'item_name'};
$item_number = $form{'item_number'};
$item_quantity = $form{'quantity'};
$pending_reason = $form{'pending_reason'};
$payment_status = $form{'payment_status'};
$payment_amount = $form{'mc_gross'};
$payment_currency = $form{'mc_currency'};
$payment_date = $form{'payment_date'};
$first_name = $form{'first_name'};
$last_name = $form{'last_name'};
$address_street = $form{'address_street'};
$address_city = $form{'address_city'};
$address_state = $form{'address_state'};
$address_zip = $form{'address_zip'};
$address_country = $form{'address_country'};
$txn_id = $form{'txn_id'};
$payer_email = $form{'payer_email'};
if ($res->is_error) {
# HTTP ERROR OCCURED (SCRIPT ERROR OR SOMETHING ALONG THEM LINES)
&error("An HTTP error occured");
}
elsif ($res->content eq 'VERIFIED') {
if ($receiver_email ne $paypal_email){&error("Your payment has been made but it was paid into the wrong paypal account")};
if ($payment_status eq 'Completed'){
# PUT CODE HERE TO CHECK $txn_id HAS NOT BEED PROCESSED BEFORE (SEE BELOW)
# YOU NEED TO KEEP A FILE THAT STORES ALL TRANSACTIONS ($txn_id) AND COMPARE THEM WITH
# THE CURRENT $txn_id TO CHECK IT DOESN'T ALREADY EXIST. IM NOT SURE WHAT YOU DO IF
# IT DOES EXIST???
# PAYMENT WAS SUCCESSFUL
print "Content-type: text/html\n\n";
print "<h2>YOUR PAYMENT WAS ACCEPTED - Thank you</h2>\n";
# PUT CODE HERE THAT WILL UPDATE A DATABASE, SEND AN EMAIL OR WHATEVER YOU WANT
}elsif ($payment_status eq 'Pending'){
# TO MAKE THINGS SAFE WE SHOULD CHECK IF THE PAYMENT IS PENDING
# IF THE PAYMENT IS CLEARED AFTER A FEW DAYS AND BECOMES COMPLETE THEN THE
# SCRIPT WILL BE CALLED AGAIN WITH A 'COMPLETE' STATUS AND THE FUNDS WILL BE ADDED TO YOUR ACCOUNT
# SO IT WOULD BE BEST TO LET THE CUSTOMER KNOW ABOUT THE PAYMENT PENDING
&error("YOUR PAYMENT IS PENDING - As soon as it is completed you will recieve confirmation via email");
}else{
# THIS WILL ONLY HAPPEN IF THE PAYMENT IS VERIFIED BUT THE STATUS OF THE PAYMENT
# IS ANYTHING ELSE BUT 'COMPLETE' OR 'PENDING'
&error("Your payment was not accepted");
}
}
elsif ($res->content eq 'INVALID') {
# PAYPAL DECLINED THE PAYMENT
&error("Your payment was not accepted");
}
else {
# YOU GUESSED IT - UNKNOWN ERROR
&error("An unknown error occurred");
}
sub error {
$error=$_[0];
print "Content-type: text/html\n\n";
print "<h2>$error</h2>\n";
exit;
}
###############################################################
###################### PARSE FORM DATA ########################
###############################################################
sub parse {
my $temp;
my @data;
foreach $temp (split(/&|=/,$query)) {
$temp =~ tr/+/ /;
$temp =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
$temp =~ s/[\r\n]/ /g;
push @data, $temp;
}
return @data;
}
the names "coder" ... "sloppy coder"
|
|
|
|
|
|
|
|
|
Rank: Starting Member
Groups: Registered
Joined: 9/29/2004 Posts: 10 Location: ,
|
Code has a error on it change this line: $req = new HTTP::Request 'POST','http://www.paypal.com/cgi-bin/webscr'';
To: $req = new HTTP::Request 'POST','http://www.paypal.com/cgi-bin/webscr';
|
|
|
|
Rank: Starting Member
Groups: Registered
Joined: 2/13/2004 Posts: 109 Location: ,
|
Hi Neeta, You may want to look at the Payment Data Transfer (PDT) feature and the variables "return" and "rm". See pages 80 and 115 of the Merchant User Manual and Integration Guide for more information (https://www.paypal.com/en_US/pdf/integration_guide.pdf). If you are not experienced with CGI, I recommend acquiring the services of an experienced Webmaster or sysadmin to assist you. Dave Burchell PayPal Technical Support PayPal, an eBay company Order PayPal Hacks now! http://www.oreilly.com/catalog/payhks/
|
|
|
|
Rank: Starting Member
Groups: Registered
Joined: 1/20/2005 Posts: 3 Location: ,
|
Hi, I am getting Software error: Global symbol "$query" requires explicit package name at /compass/web/lt23/cgi-bin/return_fullparticipant.cgi line 20. Global symbol "$query" requires explicit package name at /compass/web/lt23/cgi-bin/return_fullparticipant.cgi line 21. BEGIN not safe after errors--compilation aborted at /compass/web/lt23/cgi-bin/return_fullparticipant.cgi line 25.
my cgi code is:
#!/usr/bin/perl -wT
use strict; use CGI; use DBI;
use CGI::Carp qw(fatalsToBrowser carpout); #open (LOG,">>/file path") || open (LOG,">>/www/file path.log") || die "couldn't open log file: $!"; carpout(LOG);
$ENV{PATH} = "/bin:/usr/bin";
#$paypal_email = 'xyz@domain.edu'; # THIS IS OUR EMAIL ADDRESS WE SIGNED UP WITH PAYPAL # THIS IS USED TO CHECK THAT THE FUNDS HAVE BEEN PAID TO US AND NOT SOMEONE ELSE TRYING TO RIP US OFF
# READ DATA POSTED FROM PAYPAL read (STDIN, $query, $ENV{'CONTENT_LENGTH'}); $query .= '&cmd=_notify-validate';
# SEND DATA BACK TO PAYPAL TO VALIDATE THE PAYMENT # USE THIS MODULE use LWP::UserAgent;
# CREATE A NEW USER OBJECT VIA $ua $ua = new LWP::UserAgent;
# CREATE A NEW REQUEST OBJECT '$req' with METHOD (POST) and URL $req = new HTTP::Request 'POST','http://www.paypal.com/cgi-bin/webscr';
# ASSIGN THIS 'content_type' method to request object '$req' $req->content_type('application/x-www-form-urlencoded');
# ASSIGN THIS 'content' method to request object '$req' $req->content($query);
# TELL THE AGENT TO MAKE A REQUEST. IT RETURNS THE RESPONSE OBJECT '$res' $res = $ua->request($req);
# GET POSTED DATA FROM PAYPAL %form = &parse;
$paypal_email = 'xyz@domain.edu'; # THIS IS OUR EMAIL ADDRESS WE SIGNED UP WITH PAYPAL # VARIABLES SENT FROM PAYPAL ABOUT THE PAYMENT TO US $receiver_email = $form{'receiver_email'}; $item_name = $form{'item_name'}; #$item_quantity = $form{'quantity'}; $pending_reason = $form{'pending_reason'}; $payment_status = $form{'payment_status'}; $payment_amount = $form{'payment_gross'}; $payment_date = $form{'payment_date'}; $first_name = $form{'first_name'}; $last_name = $form{'last_name'}; $address_street = $form{'address_street'}; $address_city = $form{'address_city'}; $address_state = $form{'address_state'}; $address_zip = $form{'address_zip'}; $address_country = $form{'address_country'}; $txn_id = $form{'txn_id'}; $payer_email = $form{'payer_email'};
# If response is PENDING, nothing happens. # Otherwise, it will be either: (an http error); VERIFIED; Completed; # Invalid; or (some other error).
if ($res->is_error) { # HTTP ERROR OCCURED (SCRIPT ERROR OR SOMETHING ALONG THEM LINES) &error("An HTTP error occured"); } # end if ($res->is_error)
elsif ($res->content eq 'VERIFIED') { if ($receiver_email ne $paypal_email){ &error("Your payment has been made but it was paid into the wrong paypal account"); }
if ($payment_status eq 'Completed') {
# CHECK THAT RECEIVER EMAIL IS OUR PAYPAL EMAIL ID if ($receiver_email eq "xyz@domain.edu") {
# CHECK $txn_id HAS NOT BEED PROCESSED BEFORE (SEE BELOW) # AND RECORDED IN A FILE THAT STORES ALL TRANSACTIONS ($txn_id) AND COMPARE THEM WITH # THE CURRENT $txn_id TO CHECK IT DOESN'T ALREADY EXIST.
&check_txn;
} # end email OK
else { &error("Your payment has been made but it was paid into the wrong paypal account"); } # end else (email)
} # END OF IF payment_status eq 'COMPLETED'
#} # END of elseif
elsif ($payment_status eq 'Pending'){
# TO MAKE THINGS SAFE WE SHOULD CHECK IF THE PAYMENT IS PENDING # IF THE PAYMENT IS CLEARED AFTER A FEW DAYS AND BECOMES COMPLETE THEN THE # SCRIPT WILL BE CALLED AGAIN WITH A 'COMPLETE' STATUS AND THE FUNDS WILL BE ADDED TO YOUR ACCOUNT # SO IT WOULD BE BEST TO LET THE CUSTOMER KNOW ABOUT THE PAYMENT PENDING &error("YOUR PAYMENT IS PENDING - As soon as it is completed you will recieve confirmation via email");
} # end of else if
} # end of else if VERIFIED
elsif ($res->content eq 'INVALID') { # PAYPAL DECLINED THE PAYMENT 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";
&error("Your payment was not accepted"); }
else { # YOU GUESSED IT - UNKNOWN ERROR &error("An unknown error occurred"); }
############################################################### ###################### PRINT ERROR MESSAGE #################### ###############################################################
sub error { $error=$_[0]; print "Content-type: text/html\n\n";
print "<h2>$error</h2>\n"; exit; }
############################################################### ###################### PARSE FORM DATA ######################## ###############################################################
sub parse { my $temp; my @data; foreach $temp (split(/&|=/,$query)) { $temp =~ tr/+/ /; $temp =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge; $temp =~ s/[\r\n]/ /g; push @data, $temp; } return @data; }
######################################################################## ###################### CHECK TRANSACTION ID & UPDATE DATABASE ########## ########################################################################
# This routine will open an order file and check to see if this # transaction number has already been entered. If not, $processed will # stay as 0. If so, it will return 1. sub check_txn { $dbh = DBI->connect("DBI:CSV:f_dirdirectory path"); $statement = "select txn_id from RegPayment where txn_id =\"$txn_id\""; $sth = $dbh->prepare($statement) or print "Can't prepare the txnid SQL\n"; $rv = $sth->execute or print "Can't execute the txnid query: $sth->errstr"; #If it finds previous txn_id if ($rv == 1) { $processed = 1; } #If there is not a previous txn_id. if ($rv== '0E0') {
# UPDATE A DATABASE. $statement = "insert into RegPayment (reg_type, first_name, last_name, txn_id,payment_date,early_late_reg,payment_amount,payment_status, payer_email )"; $statement .= "values (\"$item_name\",\"$first_name\", \"$last_name\", \"$txn_id\",\"$payment_date\",""early"",\"$payment_amount\", \"$payment_status\",\"$payer_email\")"; $sth = $dbh->prepare($statement) or print "Can't prepare the SQL\n"; $rv = $sth->execute or print "Can't execute the query: $sth->errstr"; print $rv, " rows inserted\n";
# PAYMENT WAS SUCCESSFUL print "Content-type: text/html\n\n";
print "<h2>YOUR PAYMENT WAS ACCEPTED - Thank you</h2>\n";
print "content-type: text/plain\n\nOK\n"; print "<html><head><title>IPN Screendump</title></head>\n";
print "<br>Your First Name: <b>$first_name</b>\n"; print "<br>Your Last Name : <b>$last_name</b>\n"; print "<br> Address : \n"; print "<br>Street: <b>$address_street</b>\n"; print "<br>City :<b>$address_city</b>\n"; print "<br>State:<b>$address_state</b>\n"; print "<br>Zip :<b>$address_zip</b>\n"; print "<br>Country: <b>$address_country</b>\n"; print "<br>Email: <b>$payer_email</b>\n"; print "<br>Registration Type: <b>$item_name</b>\n"; print "<br>Total: <b>$payment_amount</b>\n"; print "<br>Transaction Date:<b>$payment_date</b>\n"; print "<br>Transaction ID <b>$txn_id</b>\n"; print "<br>The payment status is<b>$payment_status</b>\n"; print "</body></html>\n"; } $dbh->disconnect;
} # END OF check_txn
and please tell me how to install LWP.
|
|
|
|
Rank: Starting Member
Groups: Registered
Joined: 2/13/2004 Posts: 109 Location: ,
|
Hi Neeta, When you "use strict" you need to make sure that all of your variables are declared to be a part of a package. Specifically, try putting "my" in front of the first instance of the variable $query, like this: my $query .= '&cmd=_notify-validate'; To instally LWP, you may want to try Perl's CPAN module. At your shell prompt, type: perl -MCPAN -eshell Once you have the CPAN shell started, install LWP: install LWP You may need to do this on your system as the superuser (root). If you are not the sysadmin for the system you will want to work with your sysadmin to add the LWP module. Likewise, if you are not familiar with configuring Perl, you may want to bring in an expert. Dave Burchell PayPal Technical Support PayPal, an eBay company Order PayPal Hacks now! http://www.oreilly.com/catalog/payhks/
|
|
|
|
Guest
|
YAFVision Theme by Jaben Cargman (Tiny Gecko)Powered by YAF |
YAF © 2003-2009, Yet Another Forum.NETThis page was generated in 0.448 seconds.