Paypal sandbox notify_url file not working - php

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.

Related

PayPal IPN runs repeatedly

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();

PayPal IPN php always INVALID

I've made an attempt at writing a small PayPal IPN handler however I'm always getting 'INVALID' when using the IPN simulator https://developer.paypal.com/webapps/developer/applications/ipn_simulator . I'm not sure what about the URL I'm sending back isn't right. I have looked at some Gists for this topic but they all seem a little long winded. Their docs on this are here https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNIntro/#protocol_and_arch and I think that I have followed all the steps for the protocol.
Any help is appreciated
<?php
/**
* Validates a PayPal IPN notification
* #param array $req The $_POST variable for the request
* #return String Returns the validity: 'VALID' or 'INVALID'
*/
function verifyPayPalIPN($req) {
// Base URL for the php validation
$baseURL = 'https://www.paypal.com/cgi-bin/webscr?cmd=_notify-validate';
// Loop through the POST parameters to
// create the validaton URL
$postVars = '';
foreach ($req as $key => $value) {
$postVars .= $key . '=' . urlencode($value) . '&';
}
// Strip the last & off of the URL
$postVars = substr($postVars, 0, -1);
// Send the request to PayPal to confirm
// whether the request to the script is
// from PayPal
$requestValidity = system("curl --data '$postVars' $baseURL");
return $requestValidity;
}
file_put_contents('/tmp/result.txt', verifyPayPalIPN($_POST));
?>
cmd=_notify-validate should be part of your postVars string
$baseURL = 'https://www.paypal.com/cgi-bin/webscr';
// Loop through the POST parameters to
// create the validaton URL
$postVars = 'cmd=_notify-validate';
foreach ($req as $key => $value) {
$postVars .= $key . '=' . urlencode($value) . '&';
}
The code that I have used in the past is this:
$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) {
} else if (strcmp ($res, "INVALID") == 0) {
}
}
fclose($fp);
}
Note the port no. 443 also
firstly, check if your paying enviroment and validating enviroment is the same (both sandbox or both production), if they are not, say your customer paid their order in an production enviroment, but then your PHP code trying to request a sandbox enviroment end point to verify the IPN request, then it will always end as INVALIDE

Paypal IPN custom variable is empty

So I'm trying to send a custom variable with a Paypal adaptive payment and when Paypal does its IPN with the file that I specified in the selling preferences on my Paypal account, the custom variable is empty. My Curl code works fine and the response envelope returns successful. I echoed the post fields before sending them and this is what I got (sensitive data censored):
actionType=PAY&clientDetails.applicationId=[app
ID]&clientDetails.ipAddress=[my ip]
¤cyCode=USD&feesPayer=EACHRECEIVER&memo=[my
memo]&custom=1Ad2Ad8Ad9&receiverList.receiver(0).amount=1&receiverList.receiver(0).email=[email1]&receiverList.receiver(0).primary=true&receiverList.receiver(1).amount=0.2&receiverList.receiver(1).email=[email2]&receiverList.receiver(1).primary=false&receiverList.receiver(2).amount=0.19&receiverList.receiver(2).email=[email3]&receiverList.receiver(2).primary=false&receiverList.receiver(3).amount=0.16&receiverList.receiver(3).email=[email4]&receiverList.receiver(3).primary=false&requestEnvelope.errorLanguage=en_US&returnUrl=[return
url]&cancelUrl=[cancel url]
The custom variable is in tact and exactly as I want it. On the other hand I noticed that the currencyCode field was changed to "¤cyCode" somehow. I have no clue why but when I changed it to an array and used print_r, it said currencyCode.
Anyway the problem that I'm having comes up when Paypal does its instant notification to my Confirm.php and runs the following code:
// 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) {
$strEmail = $_POST[ "payer_email" ];
if( isset( $_POST[ "custom" ] ) == true )
{
$strQuery = "UPDATE TTest SET TestField = 'posted: " . $_POST[ "custom" ] . "' WHERE id = 1";
}
// Execute
mysql_query( $strQuery );
}
else if (strcmp ($res, "INVALID") == 0) {
}
}
fclose ($fp);
}
The $_POST[ "custom" ] variable appears to be empty because it only sets TestField to "posted: " every time.

Debugging ipn.php when using paypal sandbox ipn simulator

How do I debug the ipn.php file when using the paypal sandbox ipn simulator tool?
The code looks like this:
// 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);
if (!$fp) {
// HTTP ERROR
} else {
fputs($fp, $header.$req);
while (!feof($fp)) {
$res = fgets($fp, 1024);
if (strcmp($res, "VERIFIED") == 0) {
$DBH = new PDO("mysql:host=localhost;dbname=db", "user", "pass");
$DBH - > setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$STH = $DBH - > prepare("update table2 set status = :status where tracking_id = :tracking_id");
$status = 1;
parse_str($req, $data);
$STH - > bindParam(':status', $status, PDO::PARAM_INT, 1);
$STH - > bindParam(':tracking_id', 'id_goes_here', PDO::PARAM_STR, 50);
$STH - > execute();
$DBH = null;
} else if (strcmp($res, "INVALID") == 0) {
// do something else
}
}
fclose($fp);
}
I normally use netbeans debug facility to debug, but how do I debug using the sandbox simulator? When I click send ipn from the sandbox ipn simulator, I get a message in the sandbox saying IPN successfully sent., but when I then go into my database to check the status, it's still 0.
Maybe problem is in parameter binding
$STH - > bindParam(':tracking_id', 'id_goes_here', PDO::PARAM_STR, 50);
if table 'table2' do not contain row with tracking_id = 'id_goes_here' update action will fail.
Try this
<?php
$testMode = false;
$url = 'https://www.paypal.com/cgi-bin/webscr';
if ($testMode === true)
$url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
$ipnResponse = ''; // holds the IPN response from paypal
$ipnData = array(); // array will contain the POST values for IPN
$urlParsed = parse_url($url);
$req = 'cmd=_notify-validate'; // Add 'cmd' to req (ipn command)
// Read the post from PayPal system and add them to req
foreach ($_POST as $key => $value) {
$ipnData["$key"] = $value;
$value = urlencode(stripslashes($value));
$req .= "&" . $key . "=" . $value;
}
// Open the connection to paypal
$fp = fsockopen($urlParsed['host'], "80", $errno, $errstr, 30);
// If could open the connection and check response
if ($fp) {
fputs($fp, "POST " . $urlParsed['path'] . " HTTP/1.1\r\n");
fputs($fp, "Host: " . $urlParsed['host'] . "\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: " . strlen($req) . "\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $req . "\r\n\r\n");
// Loop through the response from the server and append to variable
while (!feof($fp)) {
$ipnResponse .= fgets($fp, 1024);
}
fclose($fp);
// Valid IPN transaction.
if (preg_match('/^VERIFIED/', $ipnResponse)) {
// Some action on IPN validation - update payment status etc
die("OK. IPN Validation: Success");
}
// Invalid IPN transaction
else {
// Some action on IPN validation - update payment status etc
die("ERROR. IPN Validation: Failed");
}
}
// Else no connection, so maybe wrong url or other reasons, you can do another call later
else {
die("ERROR. IPN Connection: fsockopen error");
}
?>
In general when I want to debug a script that doesn't provide direct output in the browser, I call a simple logging function throughout the script to output variable values or help determine where errors are occurring.
When I have no idea where the script is dying, I write a line to a log file after each significant line of code. After running the script and then checking the log file I can see exactly which line caused the script to die, a very simplified example is below. Of course after everything is running smoothly all of the logging should be removed.
public function logToFile($msg){
$file = 'log.txt';
$current = file_get_contents($file);
$current .= $msg . "\n";
file_put_contents($file, $current);
}
public function doOtherStuff(){
foreach ($_POST as $key => $value) {
$ipnData["$key"] = $value;
$value = urlencode(stripslashes($value));
$req .= "&" . $key . "=" . $value;
}
logToFile("1");
$fp = fsockopen($urlParsed['host'], "80", $errno, $errstr, 30);
logToFile("2");
if ($fp) {
logToFile("3");
fputs($fp, "POST " . $urlParsed['path'] . " HTTP/1.1\r\n");
logToFile("4");
fputs($fp, "Host: " . $urlParsed['host'] . "\r\n");
logToFile("5");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
logToFile("6");
fputs($fp, "Content-length: " . strlen($req) . "\r\n");
logToFile("7");
fputs($fp, "Connection: close\r\n\r\n");
logToFile("8");
fputs($fp, $req . "\r\n\r\n");
logToFile("9");
while (!feof($fp)) {
logToFile("10");
$ipnResponse .= fgets($fp, 1024);
}
logToFile("11");
fclose($fp);
}
}

paypal ipn not getting verified

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

Categories