2

I'm running a website locally via MAMP Pro and am having issues with connecting to PayPal sandbox. I don't think you can do this locally, right?

Here's my code:

Order.php

<?php
class Order extends Application {
    private $_table = 'orders';
    private $_table_2 = 'orders_items';
    private $_table_3 = 'statuses';

    private $_basket = array();

    private $_items = array();

    private $_fields = array();
    private $_values = array();

    private $_id = null;

    public function getItems() {
        $this->_basket = Session::getSession('basket');
        if (!empty($this->_basket)) {
            $objCatalogue = new Catalogue();
            foreach($this->_basket as $key => $value) {
                $this->_items[$key] = $objCatalogue->getProduct($key);
            }
        }
    }

    public function createOrder() {
        $this->getItems();

        if (!empty($this->_items)) {
            $objUser = new User();
            $user = $objUser->getUser(Session::getSession(Login::$_login_front));

            if (!empty($user)) {
                $objBasket = new Basket();

                $this->_fields[] = 'client';
                $this->_values[] = $this->db->escape($user['id']);

                $this->_fields[] = 'vat_rate';
                $this->_values[] = $this->db->escape($objBasket->_vat_rate);

                $this->_fields[] = 'vat';
                $this->_values[] = $this->db->escape($objBasket->_vat);

                $this->_fields[] = 'subtotal';
                $this->_values[] = $this->db->escape($objBasket->_sub_total);

                $this->_fields[] = 'total';
                $this->_values[] = $this->db->escape($objBasket->_total);

                $this->_fields[] = 'date';
                $this->_values[] = Helper::setDate();

                $sql  = "INSERT INTO `{$this->_table}` (`";
                $sql .= implode("`, `", $this->_fields);
                $sql .= "`) VALUES ('";
                $sql .= implode("', '", $this->_values);
                $sql .= "')";

                $this->db->query($sql);
                $this->_id = $this->db->lastId();

                if (!empty($this->_id)) {
                    $this->_fields = array();
                    $this->_values = array();
                    return $this->addItems($this->_id);
                }
            }
            return false;
        }
        return false;
    }

    private function addItems($order_id = null) {
        if (!empty($order_id)) {
            $error = array();
            foreach($this->_items as $item) {
                $sql = "INSERT INTO `{$this->_table_2}`
                        (`order`, `product`, `price`, `qty`)
                        VALUES ('{$order_id}', '".$item['id']."', '".$item['price']."', '".$this->_basket[$item['id']]['qty']."')";
                if (!$this->db->query($sql)) {
                    $error[] = $sql;
                }
            }
            return empty($error) ? true : false;
        }
        return false;
    }

    public function getOrder($id = null) {
        $id = !empty($id) ? $id : $this->_id;
        $sql = "SELECT * FROM `{$this->_table}`
                WHERE `id` = '".$this->db->escape($id)."'";
        return $this->db->fetchOne($sql);
    }

    public function getOrderItems($id = null) {
        $id = !empty($id) ? $id : $this->_id;
        $sql = "SELECT * FROM `{$this->_table_2}`
                WHERE `order` = '".$this->db->escape($id)."'";
        return $this->db->fetchAll($sql);
    }
}

Paypal.php

<?php
class PayPal {

// environment
private $_environment = 'sandbox';

// urls
private $_url_production = 'https://www.paypal.com/cgi-bin/webscr';
private $_url_sandbox = 'https://www.sandbox.paypal.com/cgi-bin/webscr';

// url to be used
private $_url;

// transaction type : 
// _xclick = buy now buttons
// _cart = basket
private $_cmd;

// all products array
private $_products = array();

// all input fields array
private $_fields = array();

// your paypal id
private $_business = '';

// page style
private $_page_style = null;

// return url
private $_return;

// cancel url
private $_cancel_payment;

// notify url (IPN)
private $_notify_url;

// currency code
private $_currency_code = 'GBP';

// tax / vat amount for _cart
public $_tax_cart = 0;

// tax / vat amount for _xclick
public $_tax = 0;

// pre-populating checkout pages
// address1 *, address2, city *, state *, zip *
// country *, email *, first_name *, last_name *
// you have to have all required fields filled in - otherwise it won't work
public $_populate = array();

// data received from paypal
private $_ipn_data = array();

// path to the log file for ipn response
private $_log_file = null;

// result of sending data back to paypal after ipn
private $_ipn_result;










public function __construct($cmd = '_cart') {

    $this->_url = $this->_environment == 'sandbox' ?
                    $this->_url_sandbox :
                    $this->_url_production;

    $this->_cmd = $cmd;

    $this->_return = SITE_URL."/?page=return";
    $this->_cancel_payment = SITE_URL."/?page=cancel";
    $this->_notify_url = SITE_URL."/?page=ipn";
    $this->_log_file = ROOT_PATH.DS."log".DS."ipn.log";

}







public function addProduct($number, $name, $price = 0, $qty = 1) {

    switch($this->_cmd) {

        case '_cart':
        $id = count($this->_products) + 1;
        $this->_products[$id]['item_number_'.$id] = $number;
        $this->_products[$id]['item_name_'.$id] = $name;
        $this->_products[$id]['amount_'.$id] = $price;
        $this->_products[$id]['quantity_'.$id] = $qty;
        break;
        case '_xclick':
        if (empty($this->_products)) {
            $this->_products[0]['item_number'] = $number;
            $this->_products[0]['item_name'] = $name;
            $this->_products[0]['amount'] = $price;
            $this->_products[0]['quantity'] = $qty;
        }
        break;

    }

}







private function addField($name = null, $value = null) {
    if (!empty($name) && !empty($value)) {
        $field  = '<input type="hidden" name="'.$name.'" ';
        $field .= 'value="'.$value.'" />';
        $this->_fields[] = $field;
    }
}










private function standardFields() {
    $this->addField('cmd', $this->_cmd);
    $this->addField('business', $this->_business);
    if ($this->_page_style != null) {
        $this->addField('page_style', $this->_page_style);
    }
    $this->addField('return', $this->_return);
    $this->addField('notify_url', $this->_notify_url);
    $this->addField('cancel_payment', $this->_cancel_payment);
    $this->addField('currency_code', $this->_currency_code);
    $this->addField('rm', 2);

    switch($this->_cmd) {
        case '_cart':
        if ($this->_tax_cart != 0) {
            $this->addField('tax_cart', $this->_tax_cart);
        }
        $this->addField('upload', 1);
        break;
        case '_xclick':
        if ($this->_tax != 0) {
            $this->addField('tax', $this->_tax);
        }
        break;
    }

}









private function prePopulate() {
    if (!empty($this->_populate)) {
        foreach($this->_populate as $key => $value) {
            $this->addField($key, $value);
        }
    }
}











private function processFields() {
    $this->standardFields();
    if (!empty($this->_products)) {
        foreach($this->_products as $product) {
            foreach($product as $key => $value) {
                $this->addField($key, $value);
            }
        }
    }
    $this->prePopulate();
}











private function getFields() {
    $this->processFields();
    if (!empty($this->_fields)) {
        return implode("", $this->_fields);
    }
}













private function render() {
    $out  = '<form action="'.$this->_url.'" method="post" id="frm_paypal">';
    $out .= $this->getFields();
    $out .= '<input type="submit" value="Submit" />';
    $out .= '</form>';
    return $out;
}












public function run($transaction_id = null) {
    if (!empty($transaction_id)) {
        $this->addField('custom', $transaction_id);
    }
    return $this->render();
}

















}

paypal.php

This is in a folder called mod and is on my include path set in an autoloader.php file, which has method for quick access to for example the SITE_URL and ROOT_PATH

<?php
require_once('../inc/autoload.php');

// tokens
$token2 = Session::getSession('token2');
$objForm = new Form();
$token1 = $objForm->getPost('token');

if ($token2 == Login::string2hash($token1)) {

// create order
$objOrder = new Order();
if ($objOrder->createOrder()) {

    // populate order details
    $order = $objOrder->getOrder();
    $items = $objOrder->getOrderItems();


    if (!empty($order) && !empty($items)) {

        $objBasket = new Basket();
        $objCatalogue = new Catalogue();
        $objPayPal = new PayPal();


        foreach($items as $item) {
            $product = $objCatalogue->getProduct($item['product']);
            $objPayPal->addProduct(
                $item['product'], 
                $product['name'], 
                $item['price'], 
                $item['qty']
            );
        }


        $objPayPal->_tax_cart = $objBasket->_vat;


        // populate client's details
        $objUser = new User();
        $user = $objUser->getUser($order['client']);

        if (!empty($user)) {

            // get user country record
            $objCountry = new Country();
            $country = $objCountry->getCountry($user['country']);


            // pass client's details to the PayPal instance
            $objPayPal->_populate = array(
                'address1'      => $user['address_1'],
                'address2'      => $user['address_2'],
                'city'          => $user['town'],
                'state'         => $user['county'],
                'zip'           => $user['post_code'],
                'country'       => $country['code'],
                'email'         => $user['email'],
                'first_name'    => $user['first_name'],
                'last_name'     => $user['last_name']                   
            );


            // redirect client to PayPal
            echo $objPayPal->run($order['id']);



        }

    }

}   

}

And lastly...

summary.php

<?php
Login::restrictFront();

$token1 = mt_rand();
$token2 = Login::string2hash($token1);
Session::setSession('token2', $token2);

$objBasket = new Basket();

$out = array();

$session = Session::getSession('basket');

if (!empty($session)) {
$objCatalogue = new Catalogue();
foreach($session as $key => $value) {
    $out[$key] = $objCatalogue->getProduct($key);
}
}

require_once('_header.php');

?>


<?php

echo "<div id=\"cat_prod\"><h1>- ORDER SUMMARY -</h1></div>";

?>

<?php if (!empty($out)) { ?>

<div id="big_basket">

    <form action="" method="post" id="frm_basket">

        <table cellpadding="0" cellspacing="0" border="0" class="tbl_repeat">
            <tbody id="basket_table">

                <tr style="background-color: #f2f3ee;"> 

                    <th class="ta_left">Item</th>
                    <th class="ta_r">Qty</th>
                    <th class="ta_r col_15">Price</th>

                </tr>

                <?php foreach ($out as $item) { ?>

                <tr>
                    <td class="ta_left_name"><?php echo Helper::encodeHTML($item['name']); ?></td>
                    <td class="ta_left_qty" style="float:right; padding: 10px 0px 10px"><input type="text" name="qty-<?php echo $item['id']; ?>"
                    id="qty-<?php echo $item['id']; ?>" class="fld_qty"
                    value="<?php echo $session[$item['id']]['qty']; ?>" /></td>
                    <td class="ta_r">&pound;<?php echo number_format($objBasket->itemTotal($item['price'], $session[$item['id']]['qty']), 2); ?></td>

                </tr>

                <?php } ?>

                <?php if ($objBasket->_vat_rate != 0) { ?>

                <tr style="border-bottom: dashed 1px #aaa">

                    <td class="ta_left" colspan="2">Sub-total :</td>
                    <td class="ta_r bt_td">&pound;<?php echo number_format($objBasket->_sub_total, 2); ?></td>
                    <td class="ta_r bt_td">&#160;</td>

                </tr>

                <tr style="border-bottom: dashed 1px #aaa">

                    <td class="ta_left" colspan="2">VAT (<?php $objBasket->_vat_rate; ?>%) :</td>
                    <td class="ta_r bt_td">&pound;<?php echo number_format($objBasket->_vat, 2); ?></td>
                    <td class="ta_r bt_td">&#160;</td>

                </tr>

                <?php } ?>

                <tr>

                    <td class="ta_right" colspan="2"><strong>Total :</strong></td>
                    <td class="ta_r bt_td">&pound;<?php echo number_format($objBasket->_total, 2); ?></td>
                    <td class="ta_r bt_td">&#160;</td>

                </tr>


            </tbody>    
        </table>

        <div class="dev br_td">&#160;</div>

        <div class="sbm sbm_blue fl_r paypal" id="<?php echo $token1; ?>">

            <span class="btn">Proceed to Paypal</span>

        </div>

        <div class="sbm sbm_blue fl_l">

        <a href="/?page=basket" class="btn">Amend Order</a>

        </div>

    </form>

</div>

<div class="dn">
    <img src="images/loadinfo.net.gif" alt="Proceeding to Paypal" />
</div>

<?php } else { ?>

<br /><br />
<p><em>Your basket is currently empty.</em></p>

<?php } ?>

<?php
require_once('_footer.php');

?>

Basically, when I click the Proceed to Paypal button in the summary.php page it is supposed to redirect to sandbox (at the moment for local testing) and populate all their details address, name, email etc as required. What happens though is nothing bar the page updating to show an egg timer and message saying "please wait whilst we direct you to PayPal"... which is what I've coded it to change to dynamically.

I have tried echoing on many lines in paypal.php and from the network area in Firefox it is posting 200 OK when I click the button, then token id is shown in Params, but I'm getting nothing under the Response tab and am not redirected to sandbox.

Readout from Firefox on clicking button

From reading the IPNSimulator docs I don't think you can test this locally.

And, from viewing a few Stack Overflow posts like Paypal Sandbox Test Tool IPN Simulator in Localhost I think you can use ngrok to force a domain name for site URL, but am not sure how to do this.

There is also localtunnel, but I'm not sure how to use that nor even where to download it as the site is practically blank with info here...


I'm unable to check this by uploading to my server as all my paths are directed locally for files/pages... it's messed up and I can't figure out what I need to change to get all the pages working on a direct domain name/path.

Community
  • 1
  • 1
Ashley Smith
  • 113
  • 2
  • 8
  • Added all code for review... – Ashley Smith Aug 03 '15 at 02:57
  • Not a Php/Mamp dev/user, but if that Firefox screenshot is what you're expecting to _redirect_ somewhere, I don't think I see any such (redirect) in response header... – EdSF Aug 03 '15 at 14:02
  • Correct, I'm not getting any response, but it should however redirect to https://www.sandbox.paypal.com/cgi-bin/webscr when you click the Proceed to PayPal button in the summary.php page. I don't know if it's local issue, but am having issues also getting the site up to my server and working... all pages are blank as it's dynamic. It's all working locally though bar this issue, so something's not right. I've got a call with the author of the tutorial I purchased for this code, so hopefully he'll be able to help. Will catch up. Any ideas though in interim, please post...! :) – Ashley Smith Aug 03 '15 at 14:10

0 Answers0