Over the years I've integrated countless systems with PayPal. It's normally quite straight forward and hassle free. Today, however, has been a royal pain in the arse. Anyone familiar with PayPal integration will know how shocking their sandbox is. It doesn't support all the features that the live system does, it takes forever to load and their sign up system is very tempremental (I'm still awaiting a sign up email from 9 hours ago) - so, if you're wondering why everything is being done through the live system, that's why.
PayPal's IPN system works by POSTing all the relevant variables to me a couple of seconds after the users payment has been accepted. I then post the variables straight back to PayPal's systems and they give me a response of VERIFIED or INVALID, this stops someone from POSTing to my notification URL and injecting data.
The problem is that paypal always responds with 'INVALID'. I do receive payment into my PayPal account and I do receive all the variables in full.
After a good scout round and some hardcore Googling I've found plenty of thread dedicated to this problem, however there is a common trend throughout: GoDaddy. It seems GoDaddy restrict outbound HTTP connections. I'm not on GoDaddy, I'm on my own dedicated server, and there's nothing like that going on.
PayPal documentation states that the reason for an INVALID response is that the variables are being returned in the wrong order, not all variables are present, the values do not match or the encoding differs. I'm 99% sure none of these apply to me. The item name is plaintext, with no silly characters, simply 'Sandbox test'. The part of the code that puts the POST string back together is from PayPals example code, unedited.
My code is below. It is quite lengthy, I apologise.
Code: Select all
// which environment?
//$environment = 'sandbox';
$environment = 'live';
// Your paypal email
$your_paypal_email = '***';
// url for the two environments
$envurl['sandbox'] = 'www.sandbox.paypal.com';
$envurl['live'] = 'www.paypal.com';
// 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";
$header .= "Host: http://www.paypal.com\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);
// assign posted variables to local variables
# INFO ON ME
$receiver_email = (empty($_POST['receiver_email']) ? '' : $_POST['receiver_email']);
$receiver_id = (empty($_POST['receiver_id']) ? '' : $_POST['receiver_id']);
$residence_country = (empty($_POST['residence_country']) ? '' : $_POST['residence_country']);
# INFO ON TRANSACTION
$test_ipn = (empty($_POST['test_ipn']) ? '' : $_POST['test_ipn']);
$transaction_subject = (empty($_POST['transaction_subject']) ? '' : $_POST['transaction_subject']);
$txn_id = (empty($_POST['txn_id']) ? '' : $_POST['txn_id']);
$txn_type = (empty($_POST['txn_type']) ? '' : $_POST['txn_type']);
# INFO ON BUYER
$payer_email = (empty($_POST['payer_email']) ? '' : $_POST['payer_email']);
$payer_id = (empty($_POST['payer_id']) ? '' : $_POST['payer_id']);
$payer_status = (empty($_POST['payer_status']) ? '' : $_POST['payer_status']);
$first_name = (empty($_POST['first_name']) ? '' : $_POST['first_name']);
$last_name = (empty($_POST['last_name']) ? '' : $_POST['last_name']);
$address_city = (empty($_POST['address_city']) ? '' : $_POST['address_city']);
$address_country = (empty($_POST['address_country']) ? '' : $_POST['address_country']);
$address_country_code = (empty($_POST['address_country_code']) ? '' : $_POST['address_country_code']);
$address_name = (empty($_POST['address_name']) ? '' : $_POST['address_name']);
$address_state = (empty($_POST['address_state']) ? '' : $_POST['address_state']);
$address_status = (empty($_POST['address_status']) ? '' : $_POST['address_status']);
$address_street = (empty($_POST['address_street']) ? '' : $_POST['address_street']);
$address_zip = (empty($_POST['address_zip']) ? '' : $_POST['address_zip']);
# INFO ON PAYMENT
$custom = (empty($_POST['custom']) ? '' : $_POST['custom']);
$handling_amount = (empty($_POST['handling_amount']) ? '' : $_POST['handling_amount']);
$item_name = (empty($_POST['item_name']) ? '' : $_POST['item_name']);
$item_number = (empty($_POST['item_number']) ? '' : $_POST['item_number']);
$mc_currency = (empty($_POST['mc_currency']) ? '' : $_POST['mc_currency']);
$mc_fee = (empty($_POST['mc_fee']) ? '' : $_POST['mc_fee']);
$mc_gross = (empty($_POST['mc_gross']) ? '' : $_POST['mc_gross']);
$payment_date = (empty($_POST['payment_date']) ? '' : $_POST['payment_date']);
$payment_fee = (empty($_POST['payment_fee']) ? '' : $_POST['payment_fee']);
$payment_gross = (empty($_POST['payment_gross']) ? '' : $_POST['payment_gross']);
$payment_status = (empty($_POST['payment_status']) ? '' : $_POST['payment_status']);
$payment_type = (empty($_POST['payment_type']) ? '' : $_POST['payment_type']);
$protection_eligibility = (empty($_POST['protection_eligibility']) ? '' : $_POST['protection_eligibility']);
$quantity = (empty($_POST['quantity']) ? '' : $_POST['quantity']);
$shipping = (empty($_POST['shipping']) ? '' : $_POST['shipping']);
$tax = (empty($_POST['tax']) ? '' : $_POST['tax']);
# MISC INFO
$notify_version = (empty($_POST['notify_version']) ? '' : $_POST['notify_version']);
$charset = (empty($_POST['charset']) ? '' : $_POST['charset']);
$verify_sign = (empty($_POST['verify_sign']) ? '' : $_POST['verify_sign']);
// Use thise later
$error = false;
if (!$fp) {
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
// check the payment_status is Completed
if($payment_status == 'Completed'){
// check that txn_id has not been previously processed
$txn_query = "SELECT txn_id FROM paypal WHERE txn_id = '".safe($txn_id)."' LIMIT 1";
$txn_res = mysql_query($txn_query) or die(mysql_error());
$txn_num = mysql_num_rows($txn_res);
if($txn_num == 0){
// check that receiver_email is your Primary PayPal email
if($receiver_email == $your_paypal_email){
// check that payment_amount/payment_currency are correct
// ...
// process payment
$query = "
INSERT INTO paypal (
`user_id`,`date`,
`receiver_email`,`receiver_id`,
`residence_country` ,`test_ipn` ,
`transaction_subject` ,`txn_id` ,
`txn_type` ,`payer_email` ,
`payer_id` ,`payer_status` ,
`first_name` ,`last_name` ,
`address_city` ,`address_country` ,`address_country_code` ,
`address_name` ,`address_state` ,
`address_status` ,`address_street` ,
`address_zip` ,`custom` ,
`handling_amount` ,`item_name` ,
`item_number` ,`mc_currency` ,
`mc_fee` ,`mc_gross` ,
`payment_date` ,`payment_fee` ,
`payment_gross` ,`payment_status` ,
`payment_type` ,`protection_eligibility` ,
`quantity` ,`shipping` ,
`tax` ,`notify_version` ,
`charset` ,`verify_sign`
) VALUES (
'".safe($user_id)."','".time()."',
'".safe($receiver_email)."','".safe($receiver_id)."',
'".safe($residence_country)."','".safe($test_ipn)."',
'".safe($transaction_subject)."','".safe($txn_id)."',
'".safe($txn_type)."','".safe($payer_email)."',
'".safe($payer_id)."','".safe($payer_status)."',
'".safe($first_name)."','".safe($last_name)."',
'".safe($address_city)."','".safe($address_country)."','".safe($address_country_code)."',
'".safe($address_name)."','".safe($address_state)."',
'".safe($address_status)."','".safe($address_street)."',
'".safe($address_zip)."','".safe($custom)."',
'".safe($handling_amount)."','".safe($item_name)."',
'".safe($item_number)."','".safe($mc_currency)."',
'".safe($mc_fee)."','".safe($mc_gross)."',
'".safe($payment_date)."','".safe($payment_fee)."',
'".safe($payment_gross)."','".safe($payment_status)."',
'".safe($payment_type)."','".safe($protection_eligibility)."',
'".safe($quantity)."','".safe($shipping)."',
'".safe($tax)."','".safe($notify_version)."',
'".safe($charset)."','".safe($verify_sign)."'
)
";
mysql_query($query);
} else { // receiver email check
$error = true;
$err_state = 'receiver email check failed';
}
} else { // txn_id match check
$error = true;
$err_state = 'txn_id match check failed';
}
} else { // payment_status check
$error = true;
$err_state = 'payment_status check failed';
}
} else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
$error = true;
$err_state = 'HTTP is INVALID and not VERIFIED: res = '.$res.'';
}
}
fclose ($fp);
}
if($error == true){
// Log it in database
$query = "
INSERT INTO paypal_fail (
`user_id`,`date`,
`receiver_email`,`receiver_id`,
`residence_country` ,`test_ipn` ,
`transaction_subject` ,`txn_id` ,
`txn_type` ,`payer_email` ,
`payer_id` ,`payer_status` ,
`first_name` ,`last_name` ,
`address_city` ,`address_country` ,`address_country_code` ,
`address_name` ,`address_state` ,
`address_status` ,`address_street` ,
`address_zip` ,`custom` ,
`handling_amount` ,`item_name` ,
`item_number` ,`mc_currency` ,
`mc_fee` ,`mc_gross` ,
`payment_date` ,`payment_fee` ,
`payment_gross` ,`payment_status` ,
`payment_type` ,`protection_eligibility` ,
`quantity` ,`shipping` ,
`tax` ,`notify_version` ,
`charset` ,`verify_sign`, `err_state`
) VALUES (
'".safe($custom)."','".time()."',
'".safe($receiver_email)."','".safe($receiver_id)."',
'".safe($residence_country)."','".safe($test_ipn)."',
'".safe($transaction_subject)."','".safe($txn_id)."',
'".safe($txn_type)."','".safe($payer_email)."',
'".safe($payer_id)."','".safe($payer_status)."',
'".safe($first_name)."','".safe($last_name)."',
'".safe($address_city)."','".safe($address_country)."','".safe($address_country_code)."',
'".safe($address_name)."','".safe($address_state)."',
'".safe($address_status)."','".safe($address_street)."',
'".safe($address_zip)."','".safe($custom)."',
'".safe($handling_amount)."','".safe($item_name)."',
'".safe($item_number)."','".safe($mc_currency)."',
'".safe($mc_fee)."','".safe($mc_gross)."',
'".safe($payment_date)."','".safe($payment_fee)."',
'".safe($payment_gross)."','".safe($payment_status)."',
'".safe($payment_type)."','".safe($protection_eligibility)."',
'".safe($quantity)."','".safe($shipping)."',
'".safe($tax)."','".safe($notify_version)."',
'".safe($charset)."','".safe($verify_sign)."', '".safe($err_state)."'
)
";
mysql_query($query);
}
}