I have the same issue like PayPal Instant Payment Notification Warning. I have two sites. I have the ipn url set in paypal account to site1. But I'm sending notify_url in paypal form for current site. My verification code on both sites:
public function paymentCheck()
{
$request = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$request .= "&$key=$value";
}
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($request) . "\r\n\r\n";
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
if (!$fp)
return false;
else {
fputs ($fp, $header . $request);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "INVALID") == 0) {
return false;
}
}
fclose ($fp);
}
return true;
}
My sites handle ipn. All working fine. But some of paypal messages is failing and they turned it off. Do you have any ideas, what can cause warnings?
It means that for some reason PayPal is getting something other than a 200 OK response back from your script. If it looks like your script is working it could mean that all of the tasks are completing, but then an issue at the very end causes a failure that you don't even see other than the fact that PayPal isn't getting a good response back.
You need to check your web server logs for the times when your IPN script was hit and look at the results. You'll probably find a bunch of them that show 500 or something other than 200. You should also be able to see the error details there, too, and get it resolved.
Related
So, no matter what I try to do, I seem to always get INVALID from my PayPal IPN process. I have found other pages that have similar issues, however either the solution has not worked for me or it was not solved.
Here is my current php code:
include_once($_SERVER['DOCUMENT_ROOT']."/api/static.php");
include_once($_SERVER['DOCUMENT_ROOT']."/api/api.php");
$req = 'cmd=_notify-validate';
foreach($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
$header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen('ssl://www.paypal.com', 443, $errno, $errstr, 30);
if(!$fp) {
//There was an error.
$mccubedConnection->query("replace into testing (result) values (-2);");
} else {
fputs($fp, $header . $req);
while(!feof($fp)) {
$res = fgets($fp, 1024);
if(strcmp($res, "VERIFIED") == 0) {
//Valid
$mccubedConnection->query("replace into testing (result) values (1);");
} else if(strcmp($res, "INVALID") == 0) {
//Invalid
$mccubedConnection->query("replace into testing (result) values (-1);");
}
} fclose($fp);
}
$mccubedConnection->query("replace into testing (result) values (0);");
$mccubedConnection->close();
The MySQL queries are working fine, and in the database it's posting a -1 and a 0. Where my desire is for it to be posting a 1 and a 0 (This way is just temporary for my testing, I will be handling the transaction differently).
I am using the INP simulator here: https://developer.paypal.com/developer/ipnSimulator/
And supplying the correct url to where my php file is, as it is executing, but posting a -1 and 0 to the DB.
Thanks for your time!
So it appears to me that this is an issue with PayPal's simulator specifically. I have done even more research and found this post, where they mention that it works on live servers, but not within sandbox. I really hate to make assumptions and to just assume it works and to push it, but if anyone else can confirm this is true, please let me know! (btw this has been an issue on that github for almost 2 months now... quite incredible)
I am writing a WordPress plugin that processes payments through PayPal. I have a PayPal IPN script that sends an email notification (in addition to PayPal's email notification) when a payment is successful. Some of the users of my plugin are reporting that they receive multiple copies of this email notification over several days.
I discovered this problem early on when I was developing the plugin, and the solution I found was to immediately send PayPal a 200 response. (Here is some discussion of the issue: https://www.paypal-community.com/t5/About-Settings-Archive/Paypal-repeats-identical-IPN-posts/td-p/465559 ). This seems to be working fine on my test site, but obviously isn't working for all of my users.
When I use the PayPal IPN simulator, it doesn't give me any error messages.
Aside from sending the 200 response right away, is there anything I can do to stop PayPal from repeating the IPN request over and over?
Here is my code:
<?php
// Create a query var so PayPal has somewhere to go
// https://willnorris.com/2009/06/wordpress-plugin-pet-peeve-2-direct-calls-to-plugin-files
function cdashmm_register_query_var($vars) {
$vars[] = 'cdash-member-manager';
return $vars;
}
add_filter('query_vars', 'cdashmm_register_query_var');
// If PayPal has gone to our query var, check that it is correct and process the payment
function cdashmm_parse_paypal_ipn_request($wp) {
// only process requests with "cdash-member-manager=paypal-ipn"
if (array_key_exists('cdash-member-manager', $wp->query_vars) && $wp->query_vars['cdash-member-manager'] == 'paypal-ipn') {
if( !isset( $_POST['txn_id'] ) ) {
// send a 200 message to PayPal IPN so it knows this happened
header('HTTP/1.1 200 OK');
// POST data isn't there, so we aren't going to do anything else
} else {
// we have valid POST, so we're going to do stuff with it
// send a 200 message to PayPal IPN so it knows this happened
header('HTTP/1.1 200 OK');
// process the request.
$req = 'cmd=_notify-validate';
foreach($_POST as $key => $value) :
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
endforeach;
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Host: www.paypal.com\r\n";
$header .= "Connection: close\r\n\r\n";
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
if(!$fp) {
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
while(!feof($fp)) {
$res = fgets ($fp, 1024);
$fh = fopen('result.txt', 'w');
fwrite($fh, $res);
fclose($fh);
if (strcmp (trim($res), "VERIFIED") == 0) {
/* Do a bunch of WordPress stuff - create some posts, send some emails */
}
elseif(strcmp (trim($res), "INVALID") == 0) {
// probably ought to do something here
}
}
fclose ($fp);
}
}
}
}
add_action('parse_request', 'cdashmm_parse_paypal_ipn_request');
?>
You cannot stop Paypal from repeating the request. This is part of the IPN system to make sure that the transactions clear even if the site goes down. Therefore, you should store this transaction ID in the database and check to be sure you have not encountered it in the past. If you have encountered it previously, you can log that you are seeing a repeat. Otherwise, process it.
Simple idea of this using a Transactions class:
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
$value = urldecode($value);
foreach ($pp_vars as $search) {
if ($key == $search)
$$key = $value;
}
if (preg_match("/txn_id/", $key)) {
$txn_id = $value;
}
if (preg_match("/item_number/", $key)) {
$item_number = $value;
}
}
$model = new Transactions();
if ($model->exists('txid', $txn_id)) {
$res = "REPEAT";
}
$model->action[0] = $res;
$model->txid[0] = $txn_id;
$model->description[0] = $req;
$model->price[0] = $payment_gross;
$model->reviewed[0] = 0;
$model->user_id[0] = $user->id;
$model->created_at[0] = date("Y-m-d H:i:s");
$model->updated_at[0] = $model->created_at;
$model->save();
Having made a newbe error let me try again.
The website is for a non-profit and I added a PayPal "donation" page couple of years ago; done as a shopping cart (3 types of donations and/or membership). PP returns to a php script that uses the PDT data to build a thank-you page and set cookies for a double-opt-in mailing list. IPN sends the thank-you email, opt-in email, database, etc. works fine.
Now adding a PayPal option to ticket reservation pages. Again, a shopping cart that calls PayPal and seems to work fine in the sandbox; PayPal screen is as expected, and the two foo emails look correct. I pass a different return URL which gets called but bombs on the hand shake. The code is cut&past from the previous effort and based on the PayPal PDT example.
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-synch';
$header = "";
$tx_token = $_GET['tx'];
$req .= "&tx=$tx_token&at=$auth_token"; // see header for def of auth_token
// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
// If possible, securely post back to paypal using HTTPS
// Your PHP server will need to be SSL enabled
$fp = fsockopen ($socket, $port, $errno, $errstr, 30); // see header
if (!$fp)
{
// HTTP ERROR
mail($email, "PDT Error", "fsockopen error " . $errno . ": " . $errstr);
}
else
{
fputs ($fp, $header . $req);
// read the body data
$res = '';
$headerdone = false;
while (!feof($fp))
{
$line = fgets ($fp, 1024);
echo $line . "<br>";
if (strcmp($line, "\r\n") == 0)
{
// read the header
$headerdone = true;
}
else if ($headerdone)
{
// header has been read. now read the contents
$res .= $line;
}
}
The results from the added echo are:
HTTP/1.0 302 Found
Location: https://www.sandbox.paypal.com
Server: BigIP
Connection: close
Content-Length: 0
The var $auth_token, $socket and $port are set up with a "if ($test)" to switch between the sandbox and live. Obviously with 0 length payload, nothing else works.
I read here that about the new Auth_token. There are some other nits about testing for SUCCESS that I haven't gotten to, with no data to play with..
I can't remember, does the sandbox trigger the IPN? I'm getting nothing there either - set for the sandbox. Thanks for any suggestions about where to look.
I just realized that my paypal ipn handler in php doesn't work anymore (and I change nothing), I use the sample php script provided by paypal.
I tried to isolate the problem by making several test, and at this time I can say that the problem is not the "VERIFIED" or the "INVALID" thing but comes from these lines:
[...]
fputs ($fp, $header . $req);
while (!feof($fp))
{
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0)
{
// check the payment_status is Completed
[...]
Anyone know if paypal change something or why it doesn't work?
thanks'
ps: if I put my code before all the paypal tests (before the line "if (!$fp)") it just works fine
This is my code, I comment where the "database process" works and where it doesn't.
<?php
// 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 .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
// assign posted variables to local variables
$payment_status = $_POST['payment_status'];
// DATABASE PROCESS WORKS (BEFORE THE PAYPAL TESTS)
if (!$fp)
{
// HTTP ERROR
}
else
{
// DATABASE PROCESS WORKS
fputs ($fp, $header . $req);
while (!feof($fp))
{
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0)
{
// check the payment_status is 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
// DATABASE PROCESS NOT WORKING
}
else if (strcmp ($res, "INVALID") == 0)
{
// log for manual investigation
// DATABASE PROCESS NOT WORKING
}
}
fclose ($fp);
}
?>
try using the updated script on x.xom
https://www.x.com/instant-payment-notification-4
it uses CURL instead of fsock
This error occurred when server not configured properly for socket or openSSL module not configured.
OR
You can try with below code sample of using file_get_contents instead of $fp code
<?php
// 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";
}
// for live mode
$url="https://www.paypal.com/cgi-bin/webscr";
// for developement mode
$url="https://www.sandbox.paypal.com/cgi-bin/webscr";
// instead of use of fopen you can use
$res=file_get_contents($url"?".$req);
// compare response
if (strcmp (trim($res), "VERIFIED") == 0) {
// check the payment_status is 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
}
else if (strcmp (trim($res), "INVALID") == 0) {
// log for manual investigation
}
?>
if file_get_contents not working then you can use CURL for getting response...
Let me know if have any question?
Thanks
I implemented a dynamic button "buy now" (not saved in my PayPal account) with IPN and it works fine (yeah!).
Now I have a doubt about his security, because if someone change with firebug (for example) the amount value, the transaction is valid for paypal also if my IPN listener says there is a problem with amount.
My question is "Can I encrypt the form with a php / codeigniter library?"
Because I tried to check amount in the IPN listener, but the transaction on paypal continue correctly and It isn't blocked from IPN.
Here, you find a part of my listener code:
private function isVerifiedIPN(){
$req = 'cmd=_notify-validate';
$posts = $this->input->post();
foreach ($posts as $key => $value){
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
if($this->config->item('SIMULATION'))
$url = $this->config->item('SIMULATION_URL');
else
$url = $this->config->item('PRODUCTION_URL');
if(!$this->isVerifiedAmmount() ||
!$this->isPrimaryPayPalEmail() ||
!$this->isNotProcessed()){
$req = '';
}
$header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Host: $url\r\n"; //443
$header .= "Content-type: application/x-www-form-urlencoded\r\n";
$header .= "Content-length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ("ssl://$url", 443, $errno, $errstr, 30);
if (!$fp)
{
$this->sendReport("Errore connessione socket");
return FALSE;
}
else
{
fputs ($fp, $header . $req);
while (!feof($fp))
{
$res = fgets ($fp, 1024);
if (strcmp($res, "VERIFIED") == 0)
{
// transizione valida
fclose ($fp);
return TRUE;
}
else if (strcmp ($res, "INVALID") == 0)
{
$this->sendReport('Transizione non valida');
fclose ($fp);
return FALSE;
}
}
}
}
You can dynamically encrypt buttons so that people with Firebug (or similar software) can't edit them. The PayPal API library has an example of this you can use, but I can't find it again right now.
This PayPal help file explains how to get the various keys you need using your server command line.
I also found a tutorial and a certificate builder (I didn't use, so can't confirm how secure it is...)
Once you've generated your key and certificate, you need to put them on your server and set DEFAULT_EWP_PRIVATE_KEY_PATH and DEFAULT_EWP_CERT_PATH to the relevant files.
Upload the public certificate to PayPal (instructions in linked tutorials), and set DEFAULT_CERT_ID to the Cert ID it gives you for that file. It'll also give you a file you can download - add that to your server and set PAYPAL_CERT_PATH to the path for that file.
For those who find it too hard to use a library to get the encryption going, or have hosting requirement issues with getting that working, the other trick is to not encrypt, but create a hash that you pass so that you can detect tampering, and then validate this hash when the IPN comes in for processing. I explain this here:
How do I make a PayPal encrypted buy now button with custom fields?