I'm implementing an IPN listener for Paypal Adaptive Payments, I downloaded the sample code from here:
https://cms.paypal.com/cms_content/IT/it_IT/files/developer/IPN_PHP_41.txt
Then I made a transaction (with sandbox) but I think the sample is wrong because the code returns some errors in my error_log file:
[16-Jun-2013 16:11:34 UTC] PHP Warning: stripslashes() expects parameter 1 to be string, array given in /var/www/actions/IPNListener.php on line 7
[16-Jun-2013 16:11:34 UTC] PHP Notice: Undefined variable: header in /var/www/actions/IPNListener.php on line 12
[16-Jun-2013 16:11:34 UTC] PHP Notice: Undefined index: item_name in /var/www/actions/IPNListener.php on line 18
The Undefined index is not only "item_name" but ALL INDEXES!!!!!
The transaction works correctly and the IPN is called by paypal automatically after the transaction...but the paypal sample code does not work at all! Do you know how to fix it?
Try this one
<?php
//Build the data to post back to Paypal
$postback = 'cmd=_notify-validate';
// go through each of the posted vars and add them to the postback variable
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$postback .= "&$key=$value";
}
// build the header string to 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($postback) . "\r\n\r\n";
// Send to paypal or the sandbox depending on whether you're live or developing
// comment out one of the following lines
//$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);//open the connection
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
// or use port 443 for an SSL connection
//$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
if (!$fp)
{
// HTTP ERROR Failed to connect
//error handling
}
else // if we've connected OK
{
fputs ($fp, $header . $postback);//post the data back
while (!feof($fp))
{
$response = fgets ($fp, 1024);
if (strcmp ($response, "VERIFIED") == 0) //It's verified
{
//do something
}
else if (strcmp ($response, "INVALID") == 0)
{
//the Paypal response is INVALID, not VERIFIED
// This implies something is wrong
}
} //end of while
fclose ($fp);
}
?>
Related
I was trying to follow the tutorial on paypal's developer site on setting up a basic IPN listener, and it looks nearly syntax for syntax like on their example. In fact when I started receiving the errors I've been receiving, I thought I would create a new ipn listener and use just the code they have in their example to see if it was my code or not and received the same errors.
Warning: fgets(): supplied argument is not a valid stream resource in \supergate\ipn.php on line 42
Warning: feof(): supplied argument is not a valid stream resource in \supergate\ipn.php on line 39
the errors on those line numbers are for these pieces of code at those lines:
while (!feof($fp)) //line 39
{
$res = fgets($fp, 1024); //line 42
here is the rest of the entire code
<?php
//Empty Header HTTP 200 OK reponse to ack receipt of the notification
header('HTTP/1.1 200 OK');
///////////////////////////////////////////////////////
//assign payment notification values to local variables
$item_name =$_POST['item_name'];
$item_number =$_POST['item_number'];
$payment_status =$_POST['payment_status'];
$payment_ammount =$_POST['mc_gross'];
$payment_currency =$_POST['mc_currency'];
$txn_id =$_POST['txn_id'];
$receiver_email =$_POST['receiver_email'];
$payer_email =$_POST['payer_email'];
///////////////////////////////////////////////////////
//build the required ack message of notification just received
$req = 'cmd=_notify-validate'; //add 'cmd=_notify-validate' to beginning of acknowledgement
foreach ($_POST as $key => $value) { //loop through the notification nv pairs
$value = urlencode(stripcslashes($value)); //encode these values
$req .= "&$key=$value"; //add the nv pairs to the acknowledgement
}
//set up the acknowledgement request headers
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n"; //HTTP POST REQUEST
$header .="Content-Type: application/x-www-form-urlencoded\r\n";
$header .="Content-Length: " .strlen($req) . "\r\n\r\n";
// Open a socket for the acknowledgement request
$fp = fsockopen('ssl://sandbox.paypal.com', 443, $errno, $errstr, 30);
//send the http post request back to paypal for validation
fputs($fp, $header . $req);
while (!feof($fp))
{
$res = fgets($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0)
{
//WRITE TO EMAIL
*/
}
//--------------------------------------------------------------------------------------------------------------------
else if (strcmp($res,"INVALID") == 0)
{
//write to email
}
fclose($fp); //close the file
?>
Okay now the new warning I get is this:
Warning: fgets() [function.fgets]: SSL: An existing connection was forcibly closed by the remote host.
You're not checking the result of fsockopen() which returns FALSE upon failure.
$fp = fsockopen(...);
if ($fp === FALSE) {
exit("Could not open socket");
}
One clue from the documentation is the first parameter:
hostname
If OpenSSL support is installed, you may prefix the hostname with either ssl:// or tls:// to use an SSL or TLS client connection over TCP/IP to connect to the remote host.
Note that your example is using ssl:// - it is possible your server is not correctly configured with OpenSSL.
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.
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 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
I'm trying to set up the PayPal IPN on my web application, I copied from PayPal's documentation on an example PHP snippet which is found here.
However, when I'm testing with the PayPal's sandbox, sending an IPN with the simulator which is found here.
Now, when PayPal sends the IPN, I log the actions and data of the IPN, when trying to open an connection with fsockopen, it is NULL when I do var_export on it.
I don't understand why it's not going any further with the code when the fsockopen connection is NULL.
I'm using Codeigniter for my application, and this is the part of the code that fails:
if($this->uri->segment(3) == 'ipn')
{
$error_msg = '';
$error_msg .= " initiated ";
$req = 'cmd=_notify-validate';
$error_msg .= " \n\n req: " . var_export($req, true);
foreach($this->input->post() as $key => $value)
{
$value = urlencode(stripslashes($value));
$req .= "&" . $key . "=" . $value;
}
$error_msg .= " \n\n req: " . var_export($req, true);
$header = '';
$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";
$error_msg .= " \n\n headers: " . var_export($header, true);
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
$error_msg .= " \n\n fp: " . var_export($fp, true);
I use $error_msg to log the data, this is an example what is logged:
initiated
req: 'cmd=_notify-validate'
req: 'cmd=_notify-validate&test_ipn=1&payment_type=echeck&payment_date=17%3A30%3A40+Jan+03%2C+2012+PST&payment_status=Completed&address_status=confirmed&payer_status=verified&first_name=John&last_name=Smith&payer_email=buyer%40paypalsandbox.com&payer_id=TESTBUYERID01&address_name=John+Smith&address_country=United+States&address_country_code=US&address_zip=95131&address_state=CA&address_city=San+Jose&address_street=123%2C+any+street&business=seller%40paypalsandbox.com&receiver_email=seller%40paypalsandbox.com&receiver_id=TESTSELLERID1&residence_country=US&item_name=something&item_number=DX4WYSur44CQICgO2lC%2FB10NmdaiPNH3xPZXQNAlfrEqpse0xnime22zaNXDFgbRrOL4Xsz4emkhqFw4JhOSHzCtaHt9%2B0p9p8xW6R71PVbFXNyEVjkPeHNdQm32PJg&quantity=1&shipping=3.04&tax=2.02&mc_currency=USD&mc_fee=0.44&mc_gross=12.34&txn_type=web_accept&txn_id=4014130¬ify_version=2.1&custom=xyz123&invoice=abc1234&charset=windows-1252&verify_sign=An5ns1Kso7MWUdW4ErQKJJJ4qi4-AN8d2a.xggmx9Dn4AgHpvPHJHTAp'
headers: 'POST /cgi-bin/webscr HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 969
'
fp: NULL
As you can see $fp is returning NULL on the last line of the logged data. Is there any idea why this is happening?
I can confirm I have OpenSSL enabled and installed on my server:
EDIT: Just tested fsockopen on port 80 to google.com, I still get NULL with no error number or message. So this problems occurs to every URL.
EDIT #2: Tested on my server by doing this:
fsockopen('ssl://www.paypal.com/cgi-bin/webscr', 443, $errno, $errstr, 30)
A PHP Error was encountered
Severity: Warning
Message: fsockopen(): unable to connect to
ssl://www.paypal.com/cgi-bin/webscr:443 (php_network_getaddresses:
getaddrinfo failed: nodename nor servname provided, or not known)
If anyone else is having the same problem, try using HTTPS instead of SSL
$fp = fsockopen ('https://www.paypal.com', 443, $errno, $errstr, 30);
And if your testing on Paypals Sandbox use:
$fp = fsockopen ('https://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
Be careful of $config['csrf_protection'] = TRUE; this will block all external POSTS as they will not come with a CSRF token, I've had this with my paypal IPN before, I needed to enable a crude but effective way to get the callback (in config.php):
if(stripos($_SERVER["REQUEST_URI"],'/paypal') === FALSE) {
// disable CSRF for the /paypal
$config['csrf_protection'] = TRUE;
} else {
$config['csrf_protection'] = FALSE;
}
I'm guessing this could be an issue, you would get null as no data would be captured as CI reviews your $_POST/$_GET vars for security reasons.
If I misunderstood your question and am way off track, just let me know via a comment.
Check List
sandbox url: "https://www.sandbox.paypal.com/cgi-bin/webscr";
like #jakub says CSRF must be disabled for your paypal controller
IPN wont validate on localhost, however you should still get vars back.
var_dump(fsockopen ('https://www.sandbox.paypal.com/', 443, $errno, $errstr, 30));
var_dump($_POST);
The variables $errno and $errstr probably hold the reason for the failure. Echo them out with your error message.