Paypal IPN script not executing til the end - paypal

I'm trying to write a script to update my database after the payment of the customer. My problem is that after the call of curl_init nothing seems to be happening...
My code is:
$pp_url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
$ch = curl_init($pp_url);
As nothing was happening, I added some debug code in my log file, like that:
if ($ch === false) {
addLog("Curl_init returned false");
}
else {
addLog("Curl_init worked ok");
}
Problem: no message is displayed in my log file.
I receive the log file content until these lines and then nothing.
Is there a way to understand what's going on ?
Because now I'm stuck, as I don't receive anything from Paypal...
So I'm not able to test weither or not the transaction went ok.
Please, I really need some help.
Thanks

How your addLog function is working?
You may try something that look like this:
// post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Host: www.paypal.com\r\n";
$header .= "Connection: close\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
change the paypal.com adress to the sandbox one.
I never tried with curl, but it does work with fsockopen.

Related

Socket time out with IPN

Let me start by saying I am not really a developer. I pieced the below code together a few years ago and while it worked up until last week I don't really understand it. Starting last week every time I get a paypal IPN i get a 110 Connection timed out socket error!
If I got to the page directly in the browser I get the following
Warning: fsockopen() [function.fsockopen]: unable to connect to ssl://www.paypal.com:443 (Connection timed out) in paypal_ipn.php5 on line 37
Below is the code in my paypal_ipn.php5 any help would be appreciated.
<?php
error_reporting(E_ALL ^ E_NOTICE);
$email = $_GET['ipn_email'];
$header = "";
$emailtext = "";
$req = 'cmd=_notify-validate';
if(function_exists('get_magic_quotes_gpc'))
{
$get_magic_quotes_exists = true;
}
foreach ($_POST as $key => $value)
{
if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1)
{
$value = urlencode(stripslashes($value));
}
else
{
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// Post back to PayPal to validate new http 1.1
$header .= "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .="Host: www.paypal.com\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n";
$header .="Connection: closer\n\r\n";
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
if (!$fp)
{
mail("save10percent.net#gmail.com", "socket error!", "socket error!", "$errno $errstr");
}
else
{
fputs ($fp, $header . $req);
while(!feof($fp))
{
$res = fgets ($fp, 1024);
if(stristr($res, 'VERIFIED') !== FALSE)
{
//good payment process transaction
//code removed to make my post smaller
}
elseif(stristr($res, 'INVALID') !== FALSE)
{
// If 'INVALID', send an email.
mail("save10percent.net#gmail.com", "Live-INVALID IPN", "Invalid \n\n\n res = $res \n\n\n req= $req",$error_email);
}
}
}
fclose ($fp);
?>
This socket error is trying to inform you that PayPal does not recognize your SSL certificate as valid and therefore will not open a socket for you.
It appears from this snippet that you are set up for 1024 encryption which is no longer supported. The requirement starting on February 29th that all SSL certificates MUST be SHA-256 capable (2048). This means that your current SHA-128 certificate is no longer valid for use on PayPal's systems. If you don't administer your web server you'll want to contact whomever does to upgrade your certificate to one that is supported by PayPal.
https://devblog.paypal.com/upcoming-security-changes-notice/#ssl

PayPal IPN Listener won't work anymore

First, Thanks for your attention.
Comes to prob.
I'm using this IPN Listener code:
// IPN LISTENER
// intercetta le variabili IPN inviate da PayPal
$req = 'cmd=_notify-validate';
// legge l'intero contenuto dell'array POST
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
// intestazione, prepara le variabili PayPal per la validazione
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Host: www.sandbox.paypal.com\r\n"; // www.paypal.com for a live site
$header .= "Content-Length: " . strlen($req) . "\r\n";
$header .= "Connection: close\r\n\r\n";
// apre una connessione al socket PayPal
$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
// converte le variabili inviate da IPN in variabili locali
$txn_id = filter_var($_POST['txn_id'], FILTER_SANITIZE_STRING);
$payment_status = filter_var($_POST['payment_status'], FILTER_SANITIZE_STRING);
$receiver_email = filter_var($_POST['receiver_email'], FILTER_SANITIZE_EMAIL);
$payer_email = filter_var($_POST['payer_email'], FILTER_SANITIZE_EMAIL);
$first_name = filter_var($_POST['first_name'], FILTER_SANITIZE_STRING);
$last_name = filter_var($_POST['last_name'], FILTER_SANITIZE_STRING);
$address_street = filter_var($_POST['address_street'], FILTER_SANITIZE_STRING);
$address_city = filter_var($_POST['address_city'], FILTER_SANITIZE_STRING);
$address_state = filter_var($_POST['address_state'], FILTER_SANITIZE_STRING);
$address_zip = filter_var($_POST['address_zip'], FILTER_SANITIZE_STRING);
// verifica l'apertura della connessione al socket
if (!$fp) {
// se la connessione non avviene l'esecuzione dello script viene bloccata
print("connessione PayPal non avvenuta, si prega di riprovare piu' tardi");
// in alternativa รจ per esempio possibile inviare un'email al venditore
} else {
// elaborazione delle informazioni
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
// azioni in caso di risposta positiva da parte di PayPal
if (stripos($res, "VERIFIED") !== false) {
$myvariables = 1;
$anothermyvariables = "INSERT INTO MyDB ( paid, name, email, date)
VALUES ('". $txn_id ."','" . $first_name ." ". $last_name . "','" . $payer_email ."','". the_date('Y-m-d','','',FALSE) . "');";
$wpdb->query($anothermyvariables);
}
}
// azione in caso di risposta negativa da parte di PayPal else
if (stripos($res, "INVALID") !== false) {
$anothervariablesofmine = 2;
$paypalerr = "Pagamento non riuscito!"; // Payment not success!
}
}
// chiusura della sorgente di dati
fclose($fp);
It did work previously, but not now... I've tested the variables that PayPal return to my website with var_dump and payment_status=Completed. They seem ok.
I've tested if connection is established and also it works:
if (!$fp) {
ecc..
} else {
print("Connection Established");
etc....
The problem comes with variables stripos($res, "VERIFIED") stripos($res, "INVALID").
var_dump returns both as bool (false).
Looking on Sandbox profile History (of buyer and seller), all transactions results are completed. But the thing that makes me crazy is that one week later works perfectly...
I've searched about maybe some change in IPN listener port, host or variables by PayPal but seems none has changed. Right?
I wrote the IPN Listener directly in the page of buying form, this mean IPN Listener is called also without $_POST variables. Only possible reply for me is a spam protection from IPN Listener in PayPal side that blocked me, it's possible? 'Cause the Listener is called also without cmd=_notify-validate, but simply it just don't work (but made a blank call that perhaps isn't very appreciated by PayPal).
EDIT:
Sorry guys, re-debugged (God bless var_dump).
Putted var_dump in while loop so:
....
while (!feof($fp)) {
$res = fgets ($fp, 1024);
var_dump(stripos($res, "VERIFIED"));
print("<br> VERIFIED". stripos($res, "VERIFIED") ."<br>");
var_dump(stripos($res, "INVALID"));
print("<br> INVALID". stripos($res, "INVALID") ."<br>");
...
and find one VERIFIED int(0) instead of bool (false)
I have just changed
if (stripos($res, "VERIFIED") !== false) {
to
if (stripos($res, "VERIFIED") == 0) {
I think same in INVALID case.
But I'm still not sure if this is right.
That was the problem? Or may I have to change something else? May I have to use both if conditions (if == 0 and if !== false)?
PayPal Just changed VERIFIED return value?
What worked for me was to remove the connection close header, and add a trim to the response back from PP. Here are the headers:
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Host: www.paypal.com\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
Here is the fsockopen:
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
and here is the trim on the response back from PP:
if (!$fp) {
// HTTP ERROR
error_mail("Could not open socket");
//
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = trim(fgets ($fp, 1024));
}
//
// check the payment_status is Completed
// check that receiver_email is your Primary PayPal email
//
if ((strcmp ($res, "VERIFIED") == 0) && ($payment_status == "Completed") && ($receiver_email == $valid_receiver_email)) {
That worked for me.
I had a similar problem, fixed as follows :
From time to time, when my listener posts back the cmd=_notify-validate to check a new IPN, you'll get something other than "VERIFIED" or "INVALID" back.
Sometimes I get this :
'8'.chr(13).chr(10).'VERIFIED'.chr(13).chr(10).'0'.chr(13).chr(10).chr(13).chr(10)
Sometimes I get this :
'00000008'.chr(13).chr(10).'VERIFIED'.chr(13).chr(10).'00000000'.chr(13).chr(10).chr(13).chr(10))
I think if you check for those two strings in addition to "VERIFIED" or "INVALID" you'll be fine. If not, show me what you ARE getting back from paypal that is failng your stripos($res, "VERIFIED") and stripos($res, "INVALID") tests.
Also worth noting I sometimes get an error from an intermediate cache or my ISP, or paypal just times out.. so your code needs to be able to recover from that by doing cmd=_notify-validate for that IPN later.
Lastly... I struggled with IPN systems for many years. It's always a bit unreliable, the documentation is seriously wrong in a couple of places, and IPNs lag behind transactions, often by 15 minutes or more.
I have found it is far better is to use the TransactionSearch and GetTransactionDetails methods of the API.
Documentation here :
https://developer.paypal.com/docs/classic/api/merchant/GetTransactionDetails_API_Operation_NVP/
https://developer.paypal.com/docs/classic/api/merchant/TransactionSearch_API_Operation_NVP/
These are reliable and have much less lag. I have a cron job that runs every 15 minutes to check for new transactions using those methods. I also run the new transaction check every time I receive an IPN. Let me know if you want further guidance on implementing.

PDT returning 423 as first line before success?

I'm trying to get PDT working in the sandbox, and have just run afoul of the problem of using HTTP 1.1 as described here:
https://stackoverflow.com/a/14701946/391615
Having changed everything, when I create my connection to
$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
fputs ($fp, $header . $req);
// read the body data
$res = '';
while (!feof($fp))
{
$line = fgets ($fp, 1024);
// etc...
I find that the very first lines return look like this:
423
SUCCESS
mc_gross=240.00
invoice=PP0000
protection_eligibility=Partially+Eligible+-+INR+Only
address_status=unconfirmed
Any idea what the 423 is all about?
Well here we go:
PHP fsockopen() / fread() returns messed up data
Looks like it's chunked data being returned from the server

How come sandbox paypal isn't sending me IPN?

My handler and paypal had communicated for a few days ago then something happened which made the latter stopped sending IPN anymore. I tried simulating the IPN sending via my own script without the post back capability for validation using cURL. My handler is perfectly working. I also place a simple line of code(already tested via cURL) before the lines that post back to paypal so I could check paypal's response. That line of code simply records the IPN into the database. It didn't record either. It should right? Because paypal sends IPN twice. I made sure IPN is turned on in my merchant account and the link points to my handler. Now I am beginning to suspect paypal isn't sending me anything. Here's my handler:
<?php
require_once 'classes/Mysql.php';
require_once 'classes/Email.php';
$mysql = new Mysql();
$myemail = new Email();
// 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";
}
// assign posted variables to local variables
$item_name = $_POST['item_name'];
$payment_status = $_POST['txn_type'];
$payment_amount = $_POST['mc_amount3'];
$payment_currency = $_POST['mc_currency'];
$subscr_id = $_POST['subscr_id'];
$receiver_email = urldecode($_POST['receiver_email']);
$payer_email = $_POST['payer_email'];
$subscr_type = $_POST['option_selection1'];
$username = $_POST['custom'];
//Save a copy of $req to the database. If paypal sends IPN, this should at least grab the first one before validation.
$memberID = $mysql->get_member_id($username);
$mysql->test_message($req.$payment_amount.$payment_currency, $memberID, $username, $payment_amount, $payment_currency);
// 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) {
//This if block does the payment processing. If I place this before the validation/post back occurs, it doesn't work either. But it works when testing using my cURL script--- before the validation.
if($memberID)
{
if($payment_status=='subscr_signup' && $payment_currency=='USD' && !$mysql->check_if_transactionID_exists($subscr_id))
{
$mysql->activate_subscription($memberID, $subscr_id, $subscr_type, $payment_amount);
}
}
}
else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
}
}
fclose ($fp);
}
I heard so many stories paypal is so frustrating to set. Could it be that paypal is just isn't sending IPN or there's something wrong with my handler?
I've run into a similar issue-- if you dump the var $res from the line $res = fgets ($fp, 1024); you'll see HTTP/1.1 200 OK, not the VERIFIED/INVALID that you're looking for.
Try checking out this answer for more info: Paypal IPN returning HTTP/1.1 200 OK

PayPal IPN "FAIL"

I'm trying to figure out how to use PayPal's IPN and I've run into a wall.
I want a buyer to be forwarded to a success page after making a purchase, and I want that page to show the details of their transaction. I choose IPN instead of the PDT because I also want to do some other behind the scenes stuff with their data.
Anyway, here's the code I'm using -- I'm testing in sandbox mode -- but it returns "FAIL" every time.
$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 ('www.sandbox.paypal.com', 80, $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!
echo "Validated!";
}
else if (strcmp ($res, "INVALID") == 0) {
// PAYMENT INVALID & INVESTIGATE MANUALY!
echo "Invalid!";
}
}
fclose ($fp);
}
i got the same problem in the test enviroment because my item_name has especial character,
then i change item_name to only english word and number. it works fine.
but in real enviroment i still find this problem,i read the https://www.x.com/docs/DOC-1551, but i still don't know why
I didn't realize that the sandbox account I set up was Unverified. I re-made the pre-configured sandbox account and then it started to work perfectly.