Paypal IPN Nightmare
I am having a nightmare trying to get a Paypal IPN listener to work properly. The code I have thus far is as follows (forgive the lengthy code post):
require_once('../Connections/dpp.php');
mysql_select_db($database_dpp, $dpp);
if (!function_exists("GetSQLValueString")) {
function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "")
{
if (PHP_VERSION < 6) {
$theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue;
}
$theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue);
switch ($theType) {
case "text":
$theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
break;
case "long":
case "int":
$theValue = ($theValue != "") ? intval($theValue) : "NULL";
break;
case "double":
$theValue = ($theValue != "") ? doubleval($theValue) : "NULL";
break;
case "date":
$theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
break;
case "defined":
$theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue;
break;
}
return $theValue;
}
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
// post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
// If testing on Sandbox use:
$header .= "Host: www.sandbox.paypal.com:443\r\n";
//$header .= "Host: www.paypal.com:443\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
// If testing on Sandbox use:
$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
//$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
// assign posted variables to local variables
$business = @$_POST['business'];
$payment_status = @$_POST['payment_status'];
$mc_gross = @$_POST['mc_gross'];
$payment_currency = @$_POST['mc_currency'];
$txn_id = @$_POST['txn_id'];
$receiver_email = @$_POST['receiver_email'];
$receiver_id = @$_POST['receiver_id'];
$quantity = @$_POST['quantity'];
$num_cart_items = @$_POST['num_cart_items'];
$payment_date = @$_POST['payment_date'];
$first_name = @$_POST['first_name'];
$last_name = @$_POST['last_name'];
$payment_type = @$_POST['payment_type'];
$payment_status = @$_POST['payment_status'];
$payment_gross = @$_POST['payment_gross'];
$payment_fee = @$_POST['payment_fee'];
$settle_amount = @$_POST['settle_amount'];
$memo = @$_POST['memo'];
$payer_email = @$_POST['payer_email'];
$txn_type = @$_POST['txn_type'];
$payer_status = @$_POST['payer_status'];
$address_street = @$_POST['address_street'];
$address_city = @$_POST['address_city'];
$address_state = @$_POST['address_state'];
$address_zip = @$_POST['address_zip'];
$address_country = @$_POST['address_country'];
$address_status = @$_POST['address_status'];
$item_number = @$_POST['item_number'];
$tax = @$_POST['tax'];
$option_name1 = @$_POST['option_name1'];
$option_selection1 = @$_POST['option_selection1'];
$option_name2 = @$_POST['option_name2'];
$option_selection2 = @$_POST['option_selection2'];
$for_auction = @$_POST['for_auction'];
$invoice = @$_POST['invoice'];
$custom = @$_POST['custom'];
$notify_version = @$_POST['notify_version'];
$verify_sign = @$_POST['verify_sign'];
$payer_business_name = @$_POST['payer_business_name'];
$payer_id = @$_POST['payer_id'];
$mc_currency = @$_POST['mc_currency'];
$mc_fee = @$_POST['mc_fee'];
$exchange_rate = @$_POST['exchange_rate'];
$settle_currency = @$_POST['settle_currency'];
$parent_txn_id = @$_POST['parent_txn_id'];
$pending_reason = @$_POST['pending_reason'];
$reason_code = @$_POST['reason_code'];
if (!$fp) {
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
// Write transaction record to database
$fecha = date("Y")."-".date("m")."-".date("d");
$nm=0;
if ($nm == 0){
if ($txn_type == "cart"){
foreach ($_POST as $key => $value) {
$xml .= " <$key>$value</$key>".PHP_EOL;
}
$strQuery = "insert into p_paypal_payment_info(paypal_paymentstatus,paypal_buyer_email,paypal_payer_status,paypal_firstname,paypal_lastname,paypal_street,paypal_city,paypal_state,paypal_zipcode,paypal_country,paypal_mc_gross,paypal_mc_fee,paypal_memo,paypal_paymenttype,paypal_paymentdate,paypal_txnid,paypal_pendingreason,paypal_reasoncode,paypal_tax,paypal_datecreation,paypal_verify_sign,paypal_payer_id, paypal_mc_currency,paypal_post_data) values ('".$payment_status."','".$payer_email."','" .$payer_status."','".$first_name."','".$last_name."','".$address_street."','".$address_city."','".$address_state."','".$address_zip."','".$address_country."','".$mc_gross."','".$mc_fee."','".$memo."','".$payment_type."','".$payment_date."','".$txn_id."','".$pending_reason."','".$reason_code."','".$tax."','".$fecha."','".$verify_sign."','".$payer_id."','".$mc_currency."','".$req."')";
$result_payment = mysql_query($strQuery, $dpp) or die(mysql_error());
// write individual cart items to database
for ($i = 1; $i <= $num_cart_items; $i++) {
$z_test_qry = "INSERT INTO z_qry_test(qry_id, qry_text) VALUES (NULL, 'cart_items" . $num_cart_items . "')";
$result_test = mysql_query($z_test_qry, $dpp) or die(mysql_error());
$itemname = "item_name".$i;
$itemnumber = "item_number".$i;
$mc_handling = "mc_handling".$i;
$mc_gross = "mc_gross_".$开发者_如何学编程i;
$quantity = "quantity".$i;
//CODE GET TO HERE THEN APPEARS TO STOP EXECUTING
$strQueryCart = sprintf("insert into p_paypal_cart_info(cart_txnid,cart_itemnumber,cart_itemname,cart_quantity,cart_mc_handling,cart_mc_gross) values (%s, %s, %s, %s, %s, %s)", GetSQLValueString($txn_id, "text"),GetSQLValueString(@$_POST[$itemnumber], "text"),GetSQLValueString(@$_POST[$itemname], "text"), GetSQLValueString(@$_POST[$quantity], "text"), GetSQLValueString(@$_POST[$mc_handling], "text"), GetSQLValueString(@$_POST[$mc_gross], "text"));
$result_cart = mysql_query($strQueryCart, $dpp) or die(mysql_error());
} // end FOR Loop
}
}
// send mail confirmation to merchant
}
else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
$mail_From = "From: me@mybiz.com";
$mail_To = "buyer@yourbix.com";
$mail_Subject = "INVALID IPN";
$mail_Body = $req;
foreach ($_POST as $key => $value){
$emailtext .= $key . " = " .$value ."\n\n";
}
mail($mail_To, $mail_Subject, $emailtext . "\n\n" . $mail_Body, $mail_From);
}
}
fclose ($fp);
}
?>
The peculiar thing is if I run this script locally, passing the contents of the POST in the URL and processing as a GET, it works fine. I can only assume there is an issue in the code, but I can't see it and as much as I try to debug the processing (by writing data and variable values to the database as strategic points) I cannot get it to work. It gets to a point about three quarters of the way down and apprears to stop executing (as indocated by the comment in the code above). I know for a fact it doesnt execute the following line, no matter what it is.
This is based on a script grabbed from the paypaltech.com script generator so I kind of hoped it would work pretty easily.
Can anyone see what I'm doing wrong?
To get IPN to work, you need to enable it from within your paypal account. Have you done this?
Ok this is the code I used from within sandbox environment. The code is in c# but you should be able to get the idea.
string strSandbox = "https://www.sandbox.paypal.com/cgi-bin/webscr";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(strSandbox );
//Set values for the request back
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
byte[] param = Request.BinaryRead(Request.ContentLength);
string strRequest = Encoding.ASCII.GetString(param);
strRequest += "&cmd=_notify-validate";
req.ContentLength = strRequest.Length;
//Send the request to PayPal and get the response
StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII);
streamOut.Write(strRequest);
streamOut.Close();
StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream());
string strResponse = streamIn.ReadToEnd();
streamIn.Close();
if (strResponse == "VERIFIED")
{
var phone = Request.Form["item_number"].ToString();
var amountPaid = Request.Form["payment_gross"].ToString();
string credits;
var temp1 = Request.Form["item_name"].ToString();
var temp2 = temp1.Split(' ');
credits = temp2[0].ToString();
GetPurchaseRequest purchasedetails = new GetPurchaseRequest();
purchasedetails.AmountPaid = Convert.ToDouble(amountPaid);
purchasedetails.Credits = Convert.ToInt32(credits);
purchasedetails.Phone = phone;
string xmlString = XmlHelper.UploadXmlString<GetPurchaseRequest>(purchasedetails, "Purchase");
}
else if (strResponse == "INVALID")
{
//log for manual investigation
}
else
{
//log response/ipn data for manual investigation
}
OK, re-writing the script from scratch seems to have resolved the issue. The only thing I can think of is that the original version may have been trying to write invalid data types into columns in the database. Thanks for the help guys.
I know it is an old question, but I was stuck on a similar issue, and I can see the same bug in the code posted in the question.
Whilst you are posting to "ssl://www.sandbox.paypal.com" the "Host" part of the header must still read "www.paypal.com".
Odd as their current example doesn't use the "Host" part of the header and the old examples used to use the same "Host" value as the domain used in the request (which is the same as not including the "Host" value in the header).
精彩评论