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
Related
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();
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.
Can someone please tell me whats wrong with this code.
I am trying for payment integration with Paypal with html form. I have specified the notify_url, payment goes all right but i am not able to enter in this block if (strcmp($res, "VERIFIED") == 0){}
// Response from Paypl
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$value = preg_replace('/(.*[^%^0^D])(%0A)(.*)/i', '${1}%0D%0A${3}', $value); // IPN fix
$req .= "&$key=$value";
}
// assign posted variables to local variables
$data['item_name'] = $_POST['item_name'];
// 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);
if (!$fp) {
// HTTP ERROR
echo 'HTTP ERROR';
} else {
file_put_contents('test1.txt', 'test');
fputs($fp, $header . $req);
while (!feof($fp)) {
$res = fgets($fp, 1024);
if (strcmp($res, "VERIFIED") == 0) {
echo 'SUCCESS';
} else if (strcmp($res, "INVALID") == 0) {
echo 'INVALID';
}
}
fclose($fp);
}
Use CuRl method to POST data back instead of fsock here is link:https://developer.paypal.com/webapps/developer/docs/classic/ipn/ht_ipn/ or My suggestion is Use AngellaEye library which is more effective and useful for Paypal integration here is link:http://www.angelleye.com/how-to-integrate-paypal-with-php-class-library/
Download it from this link and go throgh it.
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?
I am using the following code for paypal ipn:
<?php
mysql_connect("localhost", "user", "password") or die(mysql_error());
mysql_select_db("PayPal") or die(mysql_error());
// 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.paypal.com', 443, $errno, $errstr, 30);
if (!$fp) {
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
// PAYMENT VALIDATED & VERIFIED!
}
else if (strcmp ($res, "INVALID") == 0) {
// PAYMENT INVALID & INVESTIGATE MANUALY!
}
}
fclose ($fp);
}
?>
After testing in every which way, I am getting everything to work except when:
if (strcmp ($res, "VERIFIED") == 0)
does not work
if (strcmp ($res, "VERIFIED") == 1)
WORKS
Obviously its not getting verified as I'm sending IPN from sandbox.
What could be missing?
Since you both say that strcmp($res, "VERIFIED") == 1 is true, $res is 1 character "bigger" than the string VERIFIED. My guess is that $res has a \n character at the end or something else that needs to be stripped. Try doing something like str_replace('\n', '', $res) before calling the lines with strcmp. Just thinking out loud though. If this is not working, let me know.
Fyi, PayPal has sample code online to verify an IPN in PHP using cURL.
Link: http://www.x.com/developers/paypal/documentation-tools/paypal-code-samples#instantpaymentnotification