Go Back   CodingForums.com > :: Server side development > PHP

Before you post, read our: Rules & Posting Guidelines

Reply
 
Thread Tools Rate Thread
Enjoy an ad free experience by logging in. Not a member yet? Register.
Old 10-29-2012, 12:01 AM   PM User | #1
toddbuckles
New to the CF scene

 
Join Date: Apr 2011
Posts: 6
Thanks: 0
Thanked 0 Times in 0 Posts
toddbuckles is an unknown quantity at this point
Paypal IPN listener help

I think I have tried everything, but obviously not. I have the issue narrowed to the fsocketopen part. When I use the ssl:// address in the tutorials, i get 400 bad request returned. when I use www.sandbox.paypal.com, 80... It returns

Quote:
POST /cgi-bin/webscr HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 837

cmd=_notify-validate&test_ipn=1&payment_type=instant&payment_date=10%3A32%3A00+Oct+28%2C+2012+PDT&payment_status =Completed&address_status=confirmed&paye...
Never returns "verified", although verified is passed in the original $_POST data under payer_status.

Code never makes it past if (strcmp ($res, "VERIFIED") == 0) {

Here is the code I am using...

PHP Code:
<?PHP
require '../glob.inc.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 ('www.sandbox.paypal.com'80$errno$errstr30);


// 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'];
$memnum mysql_real_escape_string($_POST['custom']);  //our users ID


if (!$fp) {
   
// HTTP ERROR
} else {
  
fputs ($fp$header.$req);
  while (!
feof($fp)) {
    
$res fgets ($fp1024);
    
 
//the two lines below are only so I can see what is going on by logging to my database.  I am not sure how to create an error log file.
    
$payer_email $res;    
    
$log_query mysql_query("INSERT INTO ipn_log VALUES ('','".$memnum."','".$txn_id."','".$payer_email."','".$header.$req."')");
    
    if (
strcmp ($res"VERIFIED") == 0) {
    
    
//code never makes it to this point.
    
        
if ($payment_status=='Completed'){
            
$txn_id_check mysql_query("SELECT 'txn_id' FROM 'log' WHERE 'txn_id'='".$txn_id."'");
            if (
mysql_num_rows($txn_id_check)!=1){
                
                if (
$receiver_email == 'myemailaddress'){
                    
                    
//if ($payment_amount == '20.00' && $payment_currency == 'USD') {
                        //add txn_id to database log table
                        
$log_query mysql_query("INSERT INTO ipn_log VALUES ('','".$memnum."','".$txn_id."','".$payer_email."')");
                        
//update paid field
                        
$update_paid mysql_query("UPDATE members SET cknum='".$txn_id."', Amount='".$payment_amount." WHERE 'memid'='".$memnum."'");
                    
//}
                
                
}
            }    
        }
    }
    else if (
strcmp ($res"INVALID") == 0) {
         
// log for manual investigation
    
}
  }
  
fclose ($fp);
}
?>
Any help you can give would certainly be appreciated.

Thanks in advance,

TB
toddbuckles is offline   Reply With Quote
Old 11-09-2012, 02:11 PM   PM User | #2
toddbuckles
New to the CF scene

 
Join Date: Apr 2011
Posts: 6
Thanks: 0
Thanked 0 Times in 0 Posts
toddbuckles is an unknown quantity at this point
Just in case someone stumbles on this and has the same problem, I was unable to resolve it. Instead, I went the cURL route, and it worked beautifully. I am not sure why the difference, but it solved the problem. Since I had no experience with cURL, it was a learning curve for me, but I made it through.

Here is my code that worked: I connect through a glob.inc.php, search that for more info.

PHP Code:

// STEP 1: Read POST data

// reading posted data directly from $_POST causes serialization issues with array data in POST
// read raw POST data from input stream instead. 
$raw_post_data file_get_contents('php://input'); //read-only stream that allows you to read raw data from the request body.  Result is a string...
$raw_post_array explode('&'$raw_post_data);  //put the string into an array
$myPost = array();
foreach (
$raw_post_array as $keyval) {
  
$keyval explode ('='$keyval);
  if (
count($keyval) == 2)
     
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
// read the post from PayPal system and add 'cmd'
$req 'cmd=_notify-validate';
if(
function_exists('get_magic_quotes_gpc')) {
   
$get_magic_quotes_exists true;

foreach (
$myPost 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";
}

 
// STEP 2: Post IPN data back to paypal to validate

$ch curl_init('https://www.paypal.com/cgi-bin/webscr');  //initialize the curl session, and store it in object $ch

//below are the options applied to $ch
curl_setopt($chCURLOPT_HTTP_VERSIONCURL_HTTP_VERSION_1_1); //pretty obvious, sets http version.  paypal requires 1.1

curl_setopt($chCURLOPT_POST1);  //tells curl to do a regular post (the 1 option indicates 'true'

curl_setopt($chCURLOPT_RETURNTRANSFER,1);  //maybe someone can explain, manual states 'TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it out directly.'

curl_setopt($chCURLOPT_POSTFIELDS$req); //finally, the data we are posting.  Parsed above in the foreach statements

curl_setopt($chCURLOPT_SSL_VERIFYPEER1); //set to true here to verify paypal certificate

curl_setopt($chCURLOPT_SSL_VERIFYHOST2);  //could use help here.  paypal states 1 to check the existence of a common name in the SSL peer certificate. 2 to check the existence of a common name and also verify that it matches the hostname provided. In production environments the value of this option should be kept at 2 (default value).

curl_setopt($chCURLOPT_FORBID_REUSE1); //closes the connection as soon as it is finished processing without pooling data

curl_setopt($chCURLOPT_HTTPHEADER, array('Connection: Close')); //adds connection close to header

// In wamp like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path 
// of the certificate as shown below.
// curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');

if( !($res curl_exec($ch)) ) {  //and, we execute the cURL with all options set as above and log an error if it comes back empty.  Should return 'VERIFIED'
    // error_log("Got " . curl_error($ch) . " when processing IPN data");
    
curl_close($ch);
    exit;
}
curl_close($ch);

// STEP 3: Inspect IPN validation result and act accordingly

if (strcmp ($res"VERIFIED") == 0) {

     
// 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'];
    
$payment_date date('Y-m-d'strtotime($_POST['payment_date']));
    
$memid mysql_real_escape_string($_POST['custom']);  //our users ID
    
    // check whether the payment_status is Completed
    
if ($payment_status=='Completed'){
        
// check that txn_id has not been previously processed
        
$txn_id_check mysql_query("SELECT 'cknum' FROM 'members' WHERE 'cknum'='".$txn_id."'"); //cknum is a field specific to my db.
        
if (mysql_num_rows($txn_id_check)!=1){  //we don't already have that txn_id stored
            // check that receiver_email is your Primary PayPal email
            
if ($receiver_email == 'yourpaypalemail@here.com'){
                
// check that payment_amount/payment_currency are correct
                
if ($payment_amount == 'your amount' && $payment_currency == 'USD') {
                    
// process payment
                    //add values to database members table
                    
$log_query mysql_query("UPDATE members SET receipt='Yes', Amount='$payment_amount', paytype='Paypal', cknum='$txn_id', paid_thru='$payment_date' WHERE memid='$memid'");    //or whatever our sql statement is, or an email string, or whatever you want to execute.                
                
}
            }
        }    
    }
} else if (
strcmp ($res"INVALID") == 0) {
    
// log for manual investigation
    
$memid mysql_real_escape_string($_POST['custom']);  //our users ID
    
$log_query mysql_query("UPDATE members SET receipt='No', cknum='INVALID' WHERE memid='$memid'");
}
?> 
I really hope this helps someone.

TB
toddbuckles is offline   Reply With Quote
Old 11-09-2012, 11:40 PM   PM User | #3
Fumigator
UE Antagonizer


 
Fumigator's Avatar
 
Join Date: Dec 2005
Location: Utah, USA, Northwestern hemisphere, Earth, Solar System, Milky Way Galaxy, Alpha Quadrant
Posts: 7,686
Thanks: 42
Thanked 637 Times in 625 Posts
Fumigator is a glorious beacon of lightFumigator is a glorious beacon of lightFumigator is a glorious beacon of lightFumigator is a glorious beacon of lightFumigator is a glorious beacon of light
Thanks for posting the solution you ended up using. I'm not sure why using fsockopen() wouldn't work for you-- nothing jumped out at me. It's what I use and I have no problems with it.
__________________
Fumigator is offline   Reply With Quote
Old 11-09-2012, 11:57 PM   PM User | #4
minder
Banned

 
Join Date: Oct 2012
Posts: 81
Thanks: 0
Thanked 4 Times in 4 Posts
minder can only hope to improve
Quote:
Originally Posted by Fumigator View Post
Thanks for posting the solution you ended up using. I'm not sure why using fsockopen() wouldn't work for you-- nothing jumped out at me. It's what I use and I have no problems with it.
[ot]

My ISP has fsockopen disabled by default on its hosting accounts citing security reasons.

After I submitted a support ticket explaining why I needed it enabled on my hosting account (all legitimate reasons), they enabled it on my account. Perhaps the op's hosting account also has fsockopen disabled.

[/ot]
minder is offline   Reply With Quote
Old 11-10-2012, 12:59 AM   PM User | #5
felgall
Master Coder

 
felgall's Avatar
 
Join Date: Sep 2005
Location: Sydney, Australia
Posts: 5,459
Thanks: 0
Thanked 498 Times in 490 Posts
felgall is a jewel in the roughfelgall is a jewel in the roughfelgall is a jewel in the rough
A lot of web hosts only have fsocketopen enabled for specific ports - although 80 is probably the one that they are most likely to have open if they allow it on any. The hosts I have used have only ever allowed it on shared hosting on ports 80 and 443.

In my experience cURL is more likely to be disabled on the hosting which is presumably why Paypal used fsocketopen instead in their example code.
__________________
Stephen
Learn Modern JavaScript - http://javascriptexample.net/
Helping others to solve their computer problem at http://www.felgall.com/
felgall is offline   Reply With Quote
Reply

Bookmarks

Jump To Top of Thread


Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 11:43 PM.


Advertisement
Log in to turn off these ads.