• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1620
  • Last Modified:

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

0
birwin
Asked:
birwin
  • 8
  • 5
  • 3
1 Solution
 
Loganathan NatarajanLAMP DeveloperCommented:
0
 
birwinAuthor Commented:
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);
}
?>
0
 
Loganathan NatarajanLAMP DeveloperCommented:
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...
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
birwinAuthor Commented:
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?
 
0
 
Sudaraka WijesingheWeb Application ProgrammerCommented:
I think it's https://www.paypal.com not ssl://www.paypal.com
0
 
Loganathan NatarajanLAMP DeveloperCommented:
yes, it is https://palpal.com
0
 
birwinAuthor Commented:
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
0
 
birwinAuthor Commented:
Note: The page on my site is not ssl. Does it need to be?
0
 
Sudaraka WijesingheWeb Application ProgrammerCommented:
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

0
 
birwinAuthor Commented:
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?
0
 
Sudaraka WijesingheWeb Application ProgrammerCommented:
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.
0
 
birwinAuthor Commented:
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

0
 
Sudaraka WijesingheWeb Application ProgrammerCommented:
Hi birwin,

1. You can use paypal sandbox to simulate IPN. It allow you to set each parameter so you can simulate different types of IPN calls.
https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session

2. You get the "No Data" message because you are trying to process IPN on the customer's approved page. You may have configured the customer approved page as the IPN handler, but PayPal won't send IPN data back to this page with the customer (or in other words, the same session as customer returning to your page).
IPN will be sent in a separate HTTP request, which you will not see. Only way to monitor that is to log the incoming HTTP POST data to a file or DB.

3. In order to specify IPN handling Url with each shopping cart or buy now request, you have to use the notify_ur parameter like below. It has to be in the html from that you post to PayPal.
<input type="hidden" name="notify_url" value="http://domain/pagename" />

4. Is the token you mentioned a 13 character alphanumeric string? If so, that would be your receiver id, which you can use to verify the IPN requests to make sure that they belong to your merchant account.

I have attached a code of a IPN handling page from one of my sites. It just log the transaction in DB and let PayPal know all is done.

Feel free to ask any Qs you have.

//Check parameteres to verify notification
if(
	strtoupper($_REQUEST["txn_type"])!="WEB_ACCEPT" &&
	strtoupper($_REQUEST["txn_type"])!="CART"
) exit;
if($_REQUEST["business"]!=__PAYPAL_ACCOUNT) exit;
if($_REQUEST["test_ipn"]==1) exit; //Ignore sandbox IPNs
 
//Verify Notification
$strPOSTData="";
foreach($_REQUEST as $key=>$val)
{
	if(strtoupper($key)=="PHPSESSID") continue;
	
	if(strlen($strPOSTData)>0) $strPOSTData.="&";
	$strPOSTData.="$key=$val";
}
 
//Save to DB
$objPPL=new PaypalLog();
$objPPL->add($strPOSTData);
unset($objPPL);
 
if(strtoupper($_REQUEST["payment_status"])!="COMPLETED") exit;
 
$http=curl_init(__PAYPAL_IPN_VERIFICATION_URL);
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);
 
exit;

Open in new window

0
 
birwinAuthor Commented:
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.
0
 
birwinAuthor Commented:
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.
0
 
Sudaraka WijesingheWeb Application ProgrammerCommented:
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.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

  • 8
  • 5
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now