Can't access a variable i just set?

Hey all,

I’m working on my own PayPal IPN Listener, its nowhere near finish but i have got a weird problem

Here is the class:


<?php



class IPNListener {
    const PAYPAL_REFUNDED = 0;
    const PAYPAL_COMPLETED = 1;
    const PAYPAL_REVERSED = 2;
    const PAYPAL_OTHER = 9;
    
    private $req;
    private $errorString;
    private $IsValid;

    private $receiver_email;
    private $receiver_id;
    private $txn_id;
    private $payer_email;
    private $payer_id;
    private $first_name;
    private $last_name;
    private $address_country;
    private $address_country_code;
    private $address_status;
    private $address_street;
    private $address_zip;
    private $custom;
    private $mc_gross;
    private $payment_date;
    private $payment_status;
    private $mc_currency;
    private $item_name;
    private $item_number;
    private $parent_txn_id;

    private $expectedReceiver_email = "";
    private $expectedCurrency = "";
    
    public $developerMode = false;
    public $debugInfoEnabled = false;
    private $debugData = "";
    public function __construct() {

        
    }

    public function Listen(){
        $this->Debug("Listening...");

        $this->errorString = NULL;
        $header = "";
        $this->req = 'cmd=_notify-validate';
        foreach ($_POST as $key => $value) {
            $value = urlencode(stripslashes($value));
            $this->req .= "&$key=$value";
        }
        $this->Debug("Posting back to paypal");
        // post back to PayPal system to validate
        if($this->developerMode){
            $this->Debug("We're in developer mode");
            $header .= "POST /cgi-bin/webscr HTTP/1.0\\r\
";
            $header .= "Content-Type: application/x-www-form-urlencoded\\r\
";
            $header .= "Content-Length: " . strlen($this->req) . "\\r\
\\r\
";
            $fp = fsockopen('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
        }else{
            $header .= "POST /cgi-bin/webscr HTTP/1.0\\r\
";
            $header .= "Content-Type: application/x-www-form-urlencoded\\r\
";
            $header .= "Content-Length: " . strlen($this->req) . "\\r\
\\r\
";
            $fp = fsockopen('ssl://www.paypal.com', 443, $errno, $errstr, 30);
        }


        if (!$fp) {
            $this->Debug("Got some weird HTTPS error, unable to open socket with paypal for valiation");
            $this->NewError("HTTPS Error, could not open socket back to paypal");
            return;
        }
        fputs($fp, $header . $this->req);
        while (!feof($fp)) {
            $res = fgets($fp, 1024);
            if (strcmp($res, "VERIFIED") == 0) {
                $this->Debug("Is valid");
                $this->IsValid = true;
            }else if (strcmp ($res, "INVALID") == 0) {
                $this->IsValid = false;
                $this->Debug("Its not valid");
                $this->NewError("Fake IPN Notifiction");
                return;
            }
        }
        $this->Debug("Closing Socket.");
        fclose($fp);

        //Information about Heliosbots
        $this->Debug("Getting all the info....");
        
        $this->receiver_email = mysql_real_escape_string($_POST['receiver_email']); //Heliosbots Email address. This should match whats register on paypal
        $this->receiver_id = mysql_real_escape_string($_POST['receiver_id']); // Helios PP id.
        $this->txn_id = mysql_real_escape_string($_POST['txn_id']); //PayPal Transaction ID
        echo $this->txn_id;
        //Information about the buyer
        $this->payer_email = mysql_real_escape_string($_POST['payer_email']); // payers paypal email address.
        $this->payer_id = mysql_real_escape_string($_POST['payer_id']); // payers id.
        $this->payer_status = mysql_real_escape_string($_POST['payer_status']); // payer status - have they been verified??
        $this->first_name = mysql_real_escape_string($_POST['first_name']); // buyers first name
        $this->last_name = mysql_real_escape_string($_POST['last_name']); // buyers last name
        $this->address_country = mysql_real_escape_string($_POST['address_country']); // buyers country
        $this->address_country_code = mysql_real_escape_string($_POST['address_country']); // buyers country CODE, EG: US,UK
        $this->address_status = mysql_real_escape_string($_POST['address_status']); // buyers address status? verified??
        $this->address_street = mysql_real_escape_string($_POST['address_street']); // buyers address street
        $this->address_zip = mysql_real_escape_string($_POST['address_zip']); // zip / postcode of buyer
        $this->custom = mysql_real_escape_string($_POST['custom']); // Should be the order number we send to paypal.
            //
        //Information about the payment
        $this->mc_gross = mysql_real_escape_string($_POST['mc_gross']); //HOW MUCH!?!?!!
        $this->payment_date = mysql_real_escape_string($_POST['payment_date']); // payment date - 0:12:59 Jan 13, 2009 PST
        $this->payment_status = mysql_real_escape_string($_POST['payment_status']); // payment status - "Completed"
        $this->mc_currency = mysql_real_escape_string($_POST['mc_currency']); // GBP USD EUR etc etc
        $this->item_name = mysql_real_escape_string($_POST['item_name']); //
        $this->item_number = mysql_real_escape_string($_POST['item_number']); // our product ID.
        $this->parent_txn_id = mysql_real_escape_string($_POST['parent_txn_id']);
        $this->Debug("Done getting info");
    }

    public function HasErrors() {
        return $this->errorString != NULL;
    }

    private function NewError($errMsg){
        $this->errorString = $errMsg;
    }

    public function DumpToFile(){

        $file = ".html";
        $fp = fopen($file, 'w');
        fwrite($fp, "<br /><br /><p>Error String:".$this->GetErrorString(false)."</p>");
        fwrite($fp, $this->debugData);

        fclose($fp);
    }

    public function GetStatus(){

        if(strcmp(strtoupper($this->payment_status), "COMPLETED") == 0){
            return self::PAYPAL_COMPLETED;
        }else if(strcmp(strtoupper($this->payment_status), "REFUNDED") == 0){
            return self::PAYPAL_REFUND;
        }else if(strcmp(strtoupper($this->payment_status), "REVERSED") == 0){
            return self::PAYPAL_REVERSED;
        }else{
            return self::PAYPAL_OTHER;
        }
        
    }


    public function GetReq(){
        return $this->req;
    }

    public function GetErrorString($realEscapeIt = false){
        if($realEscapeIt)
            return mysql_real_escape_string ($this->errorString);
        return $this->errorString;
    }
    public function GetIsValid(){
        return $this->IsValid;
    }
    public function GetReceiverEmail(){
        return $this->receiver_email;
    }
    public function GetReceiverId(){
        return $this->receiver_id;
    }
    public function GetTxnId(){
        return $this->txn_id;
    }
    public function GetPayerEmail(){
        return $this->payer_email;
    }
    public function GetPayerId(){
        return $this->payer_id;
    }
    public function GetFirstName(){
        return $this->first_name;
    }
    public function GetLastName(){
        return $this->last_name;
    }
    public function GetAddressCountry(){
        return $this->address_country;
    }
    public function GetAddressCountryCode(){
        return $this->address_country_code;
    }
    public function GetAddress_Status(){
        return $this->address_status;
    }
    public function GetAddressStreet(){
        return $this->address_street;
    }
    public function GetAddressZip(){
        return $this->address_zip;
    }
    public function GetCustom(){
        return $this->custom;
    }
    public function GetMcGross(){
        return $this->mc_gross;
    }
    public function GetPaymentDate(){
        return $this->payment_date;
    }
    public function GetPaymentStatus(){
        return $this->payment_status;
    }
    public function GetMcCurrency(){
        return $this->mc_currency;
    }
    public function GetItemName(){
        return $this->item_name;
    }
    public function GetItemNumber(){
        return $this->item_number;
    }
    public function GetParentTxnId(){
        return $this->parent_txn_id;
    }

    public function ReceiverEmailIsValid(){
        return strcmp(strtoupper($this->receiver_email), strtoupper($this->expectedReceiver_email)) == 0;
    }

    public function IsExpectedCurrency(){
        return strcmp(strtoupper($this->mc_currency), strtoupper($this->expectedCurrency)) == 0;
    }

    public function SetError($string){
        $this->errorString = $string;
    }

    public function Debug($txt){
        if($this->debugInfoEnabled){
           $this->debugData .= "<p>".$txt."</p>";
        }
    }
}

?>


Initialize it like so.


$ipn = new IPNListener();

$ipn->developerMode = true;
$ipn->debugInfoEnabled = true;
$ipn->Listen();//Will grab all the post stuff, send it back to paypal 
$ipn->DumpToFile();// temporary dump to file, skipping database stuff.

Now the problem i have is simple, yet confusing.

I have the following line of code inside the Listen() function


$this->txn_id = mysql_real_escape_string($_POST['txn_id']); //PayPal Transaction ID
echo $this->txn_id."<br />";//Doesn't display anything
echo mysql_real_escape_string($_POST['txn_id']);//Do display the txn id.

If i try and echo the $this-> part of above it does nothing even though i just set it? If i echo directly from $_POST it displays just fine.

I don’t understand how i can set a variable/field/property and then not be able to access it directly after?

Hope that make sense?

Thanks

Thanks for the response,

I know the postback works just fine as im getting all the info and its validating perfectly. It really nothing to do with that its the fact im setting $this->txn_id = $_POST[‘txn_id’]; but when i do echo $this->txn_id; i get nothin, even though its just been set and i can prove that by doing echo $_POST[‘txn_id’]; Its just not copying into $this->txn_id;

It probably is slightly over engineered.

I don’t know if this will help but if you haven’t already checked, make sure you have fsockopen enabled on your web hosting account otherwise it wont work.

Also, in case you haven’t seen it, this is pretty much the default ipn processing script from the Paypal website. I’m wondering if you are “over-scienceing” the process with your class.

If you are using the Paypal Sandbox for testing, set the url for your IPN listener to a php file on your server containing the code below.

If when the data received by the “listener” is flagged as “Valid” after it is sent back to Paypal for verification, then you can insert your own customised backend processing code at the comment note.

<?php
//open a logfile
$fw = fopen('ipnLogfile.txt', 'w');

// 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";
}

//output all sent data from paypal
foreach ($_POST as $key => $value) {
    fwrite($fw,$key.' = '.$value."\\r\
");
}

// post back to PayPal system to validate
//$header .= "POST /cgi-bin/webscr HTTP/1.0\\r\
";
$header .= "POST /cgi-bin/webscr HTTP/1.0\\r\
";   //*** THIS WORKS ***
//$header .= "POST https://www.paypal.com/cgi-bin/webscr, HTTP/1.0\\r\
";
$header .= "Content-Type: application/x-www-form-urlencoded\\r\
";
$header .= "Content-Length: " . strlen($req) . "\\r\
\\r\
";
//$fp = fsockopen('ssl://www.paypal.com', 443, $errno, $errstr, 30);
$fp = fsockopen ('www.sandbox.paypal.com', 80, $errno, $errstr, 30); //*** THIS WORKS ***

// 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
    fwrite($fw,"***** HTTP ERROR *****  ".$errno.' - '.$errstr."\\r\
\\r\
");
} else {
    fputs($fp, $header . $req);
    while (!feof($fp)) {
        $res = fgets($fp, 1024);

        //fwrite($fw,"r\
\\r\
res = ".$res."\\r\
\\r\
");

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

            fwrite($fw,"***** VERIFIED *****\\r\
\\r\
");

                // 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
                
                /*
                  Now do your backend data processing like update databse, release product for shipping etc etc
                */
                
        } else if (strcmp($res, "INVALID") == 0) {

            fwrite($fw,"***** INVALID *****\\r\
\\r\
");

// log for manual investigation
        }
    }
    fclose($fp);
}
fclose($fw);
?>

Noone got any idea? It’s puzzling the hell out of me?

private $txn_id;

Well, if you make it PRIVATE, you cant access it directly from outside the object, now can you? Thats what all them fancy getter and setter functions are for…

EDIT: Note to self, read the WHOLE post…

Okay… that’s… odd. Hmm.

S&G, change the private definition of that variable to protected, and see what you get… See the bottom of Example 1 on: http://www.php.net/manual/en/language.oop5.visibility.php

That didnt’t work either.

I have changed the DumpTofile method to use the TXN ID as the file name so its like 4465433.html and still nothing.

Im calling listen which should set all of the variables.
Then dumping to file and using one of the variables set as the file name (txn_id) but still i get nothing :S

I assume if you do echo $ipn->GetTxnId(); in your main script you get the same result?

Yes,

its very strange.

As you can see at the top of Listen() there is a foreach loop which gets all the POST data and throws it into $this->req - Well i can dump $this-req and it works just fine… but down below when i then use mysql_real_escape($_POST[‘’]); it acts as if $_POST is now empty. It definatley gets the to end of Listen because i get the debug info “Done getting info”.

>.<

and now i think i just figured it out.

mysql_real_escape_string requires a database connection doesn’t it.

So its not giving me anything back, i do this all the time stupid mistakes that’ll teach me for trying to throw up a testbed quickly and it taking me forever now to actually fix a problem which didn’t need fixing.

Extreme fail by me, sorry for time wasting but thank you.

http://php.net/manual/en/function.mysql-real-escape-string.php

[B]link_identifier

The MySQL connection. If the link identifier is not specified, the last link opened by mysql_connect() is assumed. If no such link is found, it will try to create one as if mysql_connect() was called with no arguments. If no connection is found or established, an E_WARNING level error is generated.[/B]

lol yes. It does require a connection be established. S’why its always a good idea to run with display_errors on while you’re developing :wink:

yesss :< enabled it now

Thanks again