Link to home
Start Free TrialLog in
Avatar of birwin
birwinFlag for Canada

asked on

PayPal Payment Approval Notification

I use PayPal on my site to accept payments. The user chooses the amount on page A and is then taken to page B, where I create the form that takes the user to PayPal with the information to process the payment (see code).

I now need to get confirmation that they payment has gone through in real time.

I have reviewed the PayPal APIs and I have not been able to integrate their code into my site to give me the notification I want. I have an API signature, password and certificate, but I can't figure out a safe way include them.

I also need to know how to poll the PayPal site to confirm the transaction completed successfully.
<form target="paypal"action="https://www.paypal.com/cgi-bin/webscr"   method="post">
   <input type="hidden" name="add" value="1">
   <input type="hidden" name="cmd" value="_cart">
   <input type="hidden" name="business" value="xxxxxx@gmail.com">
   <input type="hidden" name="item_name" value="User Credits">
   <input type="hidden" name="invoice" value="".$SESSION['username'].date("Ymd")."">
   <input type="hidden" name="amount" value="".$_POST['credit']."">
   <input type="hidden" name="return" value="http://www.xxxxxx.com/paypal_accepted.php">
<input type="hidden" name="cancel_return" value="http://www.xxxxxx.com/paypal_cancelled.php">
   <input type="hidden" name="no_shipping" value="1">
   <input type="hidden" name="no_note" value="1">
   <input type="hidden" name="currency_code" value="USD">
   <input type="hidden" name="tax" value="0">
   <input type="hidden" name="bn" value="IC_Sample">
<p>You are purchasing ".$_POST['credit']." credits from us for $".number_format($_POST['credit'], 2)." US$</p>
<p> Click the "Buy Now" Button to Complete This Transaction</p><br />
   <div class='message'><img src='images/site_logo.gif' alt='' /><input type="image" src="https://www.paypal.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="Make payments with PayPal -       it's fast, free and secure!">
   <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif width="1" height="1"></div>
</form>

Open in new window

Avatar of Loganathan Natarajan
Loganathan Natarajan
Flag of India image

Avatar of birwin

ASKER

thanks Logudotcom.
The PHP code from the PayPal site shows below. Does this go in the http://www.xxxxxx.com/paypal_accepted.php? How is that code initiated?
Do I need to send the password / username / certificate with the original post? If yes, how do I do that?
// 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);
// assign posted variables to local variables
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
if (!$fp) {
// HTTP ERROR
} else {
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
}
else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
}
}
fclose ($fp);
}
?>
After you post the values to the paypal , it will process and made transaction... you need to mention about the response page while you post...

on the response page, you need to retrieve the details (using IPN services)...

just print the response...
Avatar of birwin

ASKER

I tried this using the paypal sandbox. I put the code above in the paypal_approved.php, which is the return link from paypal.
I got this error:
Warning: fsockopen() [function.fsockopen]: unable to connect to ssl://www.paypal.com:443 (Unable to find the socket transport "ssl" - did you forget to enable it when you configured PHP?) in /home/nuggets/public_html/paypal_accepted.php on line 15
Line 15 is:
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
any idea why?
 
Avatar of birwin

ASKER

I changed it to https and got this error:
Warning: fsockopen() [function.fsockopen]: unable to connect to https://www.paypal.com:443 (Unable to find the socket transport "https" - did you forget to enable it when you configured PHP?) in /home/xxxxxx/public_html/paypal_accepted.php on line 49
Avatar of birwin

ASKER

Note: The page on my site is not ssl. Does it need to be?
try it with out any protocol specification on the host name:
$fp = fsockopen ('www.paypal.com', 443, $errno, $errstr, 30);
I think fsocketopen only accept the host name.

I always use curl as listed below (if it helps)

$http=curl_init("https://www.paypal.com/cgi-bin/webscr");
curl_setopt($http, CURLOPT_POST,1);
curl_setopt($http, CURLOPT_POSTFIELDS, $strPOSTData."&cmd=_notify-validate");
curl_setopt($http, CURLOPT_RETURNTRANSFER,1);
$strVerification=curl_exec($http);
curl_close($http);

Open in new window

Avatar of birwin

ASKER

Thank you for the suggestions.
This is getting very frustrating. I removed the ssl and https from the url and the error stopped, but I get no reponse from the program.
Using the paypal sandbox, I made a payment and returned to my site. The code about is on the landing page. I get no reponse from the code.
if I add a printout of the values
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
echo"key is $key and value is $value<br />";
$req .= "&$key=$value";
}
Nothing prints.
$res has no value.
Any idea what I am doing wrong?
Hi birwin,

Please make sure of the following:

1. IPN is enabled on your PayPal account.
2. You setup the correct callback Url (full Url, not just relative path) on the PayPal account or you are sending it with each request to PayPal from your shopping cart or what ever: <input type="hidden" name="notify_url" value="http://domain/paypal.ipn.php" />
3. Make sure paypal.com is accessible from your web server (not the browser).

Also, from what you said above, it seems you are looking for IPN data on the page that you return to from pay pal payment process (from your browser, maybe I'm wrong?) IPN is NOT sent to the Url you specify on RETURN parameter, unless of cause you configured like that, but still it won't be in the same session.
Create a page to handle the IPN post back from PayPal and write it to a text file or DB for debugging.

If possible please attache your IPN handling page also.

Hope this helps.
Avatar of birwin

ASKER

Thank you sudaraka:
I think I made this more complicated than it had to be. I was trying to use the full API when I really just need the IPN. I set up my client's account with the IPN settings, although I am using my personal developer's sandbox to test the results. Am I right to assume that the sandbox would be sending the correct IPN data? If not, how do I ask it to do so?
Below is the code I am now using, which is somewhat different than I show above. I found on the PayPal forum, the Curl code which does not create the errors. There were a number of postings that said that the fp version wouldn't work on Apache.
The code now doesn't show an error, but I get a "NO DATA" error message.
Yes, I do have the code on the customer's approved page. As I understand your comment, I should have a separate page that PayPal can post to that is different from the customer's approved page. Isn't the page indicated as the return page in the code the one that PayPal uses to return the customer to the site? If not, how do I indicate the page that PayPal should use to send me the data?
When I applied for the IPN, was given a token. I don't see any place that the token is used. Is it used in the verification process?
I appreciate your help with this.

Checkout Code:
 
<?
 
$successurl="http://www.xxxxxxxxxxxx.com/paypal_accepted.php";
$cancelurl="http://www.xxxxxxxxxx.com/paypal_cancelled.php";
 
//<form target="paypal"action="https://www.paypal.com/cgi-bin/webscr"   method="post">    
 
 
<form target="paypal"action="https://sandbox.paypal.com/cgi-bin/webscr"   method="post">
 
  <form target="paypal"action="https://sandbox.paypal.com/cgi-bin/webscr"   method="post">
   <input type="hidden" name="add" value="1">
   <input type="hidden" name="cmd" value="_cart">
   <input type="hidden" name="business" value="xxxxxx_1241074915_biz@xxxxxxxxxxxxx.com">";    
 
   echo"
   <input type="hidden" name="item_name" value="Credits">
   <input type="hidden" name="invoice" value="".$SESSION['username'].date("YmdHms")."">
   <input type="hidden" name="amount" value="".$_POST['credit']."">
   <input type="hidden" name="return" value="$successurl">
<input type="hidden" name="cancel_return" value="$cancelurl">
   <input type="hidden" name="no_shipping" value="1">
   <input type="hidden" name="no_note" value="1">
   <input type="hidden" name="currency_code" value="USD">
   <input type="hidden" name="tax" value="0">
   <input type="hidden" name="bn" value="IC_Sample">
<p>You are purchasing ".$_POST['credit']." credits from xxxxxxxx for $".number_format($_POST['credit'], 2)." US$</p>
<p> Click the "Buy Now" Button to Complete This Transaction</p><br />
   <div class='message'><img src='images/site_logo.gif' alt='' /><input type="image" src="https://www.paypal.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="Make payments with PayPal -       it's fast, free and secure!">
   <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif width="1" height="1"></div>
</form>
?>
 
 
The recieving page code has a bunch of code to dump the return data into a database, but the basic code to verify is:
 
<?
 
// read the post from PayPal system and add 'cmd'
if($_SERVER['REQUEST_METHOD']!="POST") die("No data");
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
 
// post back to PayPal system to validate
$url=(!isset($_POST['test_ipn'])) ? 'https://www.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr';
 
    $curl_result=$curl_err='';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/x-www-form-urlencoded", "Content-Length: " . strlen($req)));
    curl_setopt($ch, CURLOPT_HEADER , 0);   
    curl_setopt($ch, CURLOPT_VERBOSE, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
 
    $curl_result = @curl_exec($ch);
    $curl_err = curl_error($ch);
    curl_close($ch);
 
//are we verified? If so, let's process the IPN
if (strpos($curl_result, "VERIFIED")!==false) 
{
$APPROVED_FLAG=1;
}
?>

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Sudaraka Wijesinghe
Sudaraka Wijesinghe
Flag of Sri Lanka image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of birwin

ASKER

Thank you so much for your help. I had not understood that the IPN was separate from their API process and I was getting nowhere. Thank you for spotting the issue.
Avatar of birwin

ASKER

Hi sudaraka:
One question I had was how the response from Curl is handled. I assume that $strVerification holds some indication that the handshake was made. Do I need to test that variable to make sure it is valid?
Thank you again for your help and clarification.
Hi birwin,

curl_exec will return the HTTP POST data PayPal return to us for the _notify-validate request we sent. (because CURLOPT_RETURNTRANSFER is set to 1).
I think it would be a query string style name value pair and you can parse that for further verification if you need to.