/**
  * checkout()
  * Handles checkout process */
 function checkout($wp)
 {
     $pages = $this->Settings->get('pages');
     // If checkout page requested
     // Note: we have to use custom detection here as
     // the wp->post vars are not available at this point
     // to make use of is_shopp_page()
     if ((SHOPP_PERMALINKS && isset($wp->query_vars['pagename']) && $wp->query_vars['pagename'] == $pages['checkout']['permalink'] || isset($wp->query_vars['page_id']) && $wp->query_vars['page_id'] == $pages['checkout']['id']) && $wp->query_vars['shopp_proc'] == "checkout") {
         $this->Cart->updated();
         $this->Cart->totals();
         if ($this->Cart->data->ShippingPostcodeError) {
             header('Location: ' . $this->link('cart'));
             exit;
         }
         // Force secure checkout page if its not already
         $secure = true;
         $gateway = $this->Settings->get('payment_gateway');
         if (strpos($gateway, "TestMode") !== false || isset($wp->query_vars['shopp_xco']) || $this->Cart->orderisfree()) {
             $secure = false;
         }
         if ($secure && !$this->secure && !SHOPP_NOSSL) {
             header('Location: ' . $this->link('checkout', $secure));
             exit;
         }
     }
     // Cancel this process if there is no order data
     if (!isset($this->Cart->data->Order)) {
         return;
     }
     $Order = $this->Cart->data->Order;
     // Intercept external checkout processing
     if (!empty($wp->query_vars['shopp_xco'])) {
         if ($this->gateway($wp->query_vars['shopp_xco'])) {
             if ($wp->query_vars['shopp_proc'] != "confirm-order" && !isset($_POST['checkout'])) {
                 $this->Gateway->checkout();
                 $this->Gateway->error();
             }
         }
     }
     // Cancel if no checkout process detected
     if (empty($_POST['checkout'])) {
         return true;
     }
     // Handoff to order processing
     if ($_POST['checkout'] == "confirmed") {
         return $this->Flow->order();
     }
     // Cancel if checkout process is not ready for processing
     if ($_POST['checkout'] != "process") {
         return true;
     }
     // Cancel if processing a login from the checkout form
     if (isset($_POST['process-login']) && $_POST['process-login'] == "true") {
         return true;
     }
     // Start processing the checkout form
     $_POST = attribute_escape_deep($_POST);
     $_POST['billing']['cardexpires'] = sprintf("%02d%02d", $_POST['billing']['cardexpires-mm'], $_POST['billing']['cardexpires-yy']);
     // If the card number is provided over a secure connection
     // Change the cart to operate in secure mode
     if (isset($_POST['billing']['card']) && is_shopp_secure()) {
         $this->Cart->secured(true);
     }
     // Sanitize the card number to ensure it only contains numbers
     $_POST['billing']['card'] = preg_replace('/[^\\d]/', '', $_POST['billing']['card']);
     if (isset($_POST['data'])) {
         $Order->data = stripslashes_deep($_POST['data']);
     }
     if (empty($Order->Customer)) {
         $Order->Customer = new Customer();
     }
     $Order->Customer->updates($_POST);
     if (isset($_POST['confirm-password'])) {
         $Order->Customer->confirm_password = $_POST['confirm-password'];
     }
     if (empty($Order->Billing)) {
         $Order->Billing = new Billing();
     }
     $Order->Billing->updates($_POST['billing']);
     if (!empty($_POST['billing']['cardexpires-mm']) && !empty($_POST['billing']['cardexpires-yy'])) {
         $Order->Billing->cardexpires = mktime(0, 0, 0, $_POST['billing']['cardexpires-mm'], 1, $_POST['billing']['cardexpires-yy'] + 2000);
     } else {
         $Order->Billing->cardexpires = 0;
     }
     $Order->Billing->cvv = preg_replace('/[^\\d]/', '', $_POST['billing']['cvv']);
     if (empty($Order->Shipping)) {
         $Order->Shipping = new Shipping();
     }
     if (isset($_POST['shipping'])) {
         $Order->Shipping->updates($_POST['shipping']);
     }
     if (!empty($_POST['shipmethod'])) {
         $Order->Shipping->method = $_POST['shipmethod'];
     } else {
         $Order->Shipping->method = key($this->Cart->data->ShipCosts);
     }
     // Override posted shipping updates with billing address
     if ($_POST['sameshipaddress'] == "on") {
         $Order->Shipping->updates($Order->Billing, array("_datatypes", "_table", "_key", "_lists", "id", "created", "modified"));
     }
     $estimatedTotal = $this->Cart->data->Totals->total;
     $this->Cart->updated();
     $this->Cart->totals();
     if ($this->Cart->validate() !== true) {
         return;
     } else {
         $Order->Customer->updates($_POST);
     }
     // Catch changes from validation
     // If the cart's total changes at all, confirm the order
     if ($estimatedTotal != $this->Cart->data->Totals->total || $this->Settings->get('order_confirmation') == "always") {
         $gateway = $this->Settings->get('payment_gateway');
         $secure = true;
         if (strpos($gateway, "TestMode") !== false || isset($wp->query_vars['shopp_xco']) || $this->Cart->orderisfree()) {
             $secure = false;
         }
         shopp_redirect($this->link('confirm-order', $secure));
     } else {
         $this->Flow->order();
     }
 }
 /**
  * order()
  * Processes orders by passing transaction information to the active
  * payment gateway */
 function order($gateway = false)
 {
     global $Shopp;
     $Cart = $Shopp->Cart;
     $db = DB::get();
     do_action('shopp_order_preprocessing');
     $Order = $Shopp->Cart->data->Order;
     $Order->Totals = $Shopp->Cart->data->Totals;
     $Order->Items = $Shopp->Cart->contents;
     $Order->Cart = $Shopp->Cart->session;
     if ($Shopp->Gateway && !$Cart->orderisfree()) {
         // Use an external checkout payment gateway
         if (SHOPP_DEBUG) {
             new ShoppError('Processing order through a remote-payment gateway service.', false, SHOPP_DEBUG_ERR);
         }
         $Purchase = $Shopp->Gateway->process();
         if (!$Purchase) {
             if (SHOPP_DEBUG) {
                 new ShoppError('The remote-payment gateway encountered an error.', false, SHOPP_DEBUG_ERR);
             }
             $Shopp->Gateway->error();
             return false;
         }
         if (SHOPP_DEBUG) {
             new ShoppError('Transaction successfully processed by remote-payment gateway service.', false, SHOPP_DEBUG_ERR);
         }
     } else {
         // Use local payment gateway set in payment settings
         $gateway = $Shopp->Settings->get('payment_gateway');
         // Process a transaction if the order has a cost (is not free)
         if (!$Cart->orderisfree()) {
             if (!$Shopp->gateway($gateway)) {
                 return false;
             }
             // Process the transaction through the payment gateway
             if (SHOPP_DEBUG) {
                 new ShoppError('Processing order through local-payment gateway service.', false, SHOPP_DEBUG_ERR);
             }
             $processed = $Shopp->Gateway->process();
             // exit();
             // There was a problem processing the transaction,
             // grab the error response from the gateway so we can report it
             if (!$processed) {
                 if (SHOPP_DEBUG) {
                     new ShoppError('The local-payment gateway encountered an error.', false, SHOPP_DEBUG_ERR);
                 }
                 $Shopp->Gateway->error();
                 return false;
             }
             $gatewaymeta = $this->scan_gateway_meta(SHOPP_GATEWAYS . $gateway);
             $gatewayname = $gatewaymeta->name;
             $transactionid = $Shopp->Gateway->transactionid();
             if (SHOPP_DEBUG) {
                 new ShoppError('Transaction ' . $transactionid . ' successfully processed by local-payment gateway service ' . $gatewayname . '.', false, SHOPP_DEBUG_ERR);
             }
         } else {
             if (!$Cart->validorder()) {
                 new ShoppError(__('There is not enough customer information to process the order.', 'Shopp'), 'invalid_order', SHOPP_TRXN_ERR);
                 return false;
             }
             $gatewayname = __('N/A', 'Shopp');
             $transactionid = __('(Free Order)', 'Shopp');
         }
         $authentication = $Shopp->Settings->get('account_system');
         // Transaction successful, save the order
         if ($authentication == "wordpress") {
             // Check if they've logged in
             // If the shopper is already logged-in, save their updated customer info
             if ($Shopp->Cart->data->login) {
                 if (SHOPP_DEBUG) {
                     new ShoppError('Customer logged in, linking Shopp customer account to existing WordPress account.', false, SHOPP_DEBUG_ERR);
                 }
                 get_currentuserinfo();
                 global $user_ID;
                 $Order->Customer->wpuser = $user_ID;
             }
             // Create WordPress account (if necessary)
             if (!$Order->Customer->wpuser) {
                 if (SHOPP_DEBUG) {
                     new ShoppError('Creating a new WordPress account for this customer.', false, SHOPP_DEBUG_ERR);
                 }
                 if (!$Order->Customer->new_wpuser()) {
                     new ShoppError(__('Account creation failed on order for customer id:' . $Order->Customer->id, "Shopp"), false, SHOPP_TRXN_ERR);
                 }
             }
         }
         // Create a WP-compatible password hash to go in the db
         if (empty($Order->Customer->id)) {
             $Order->Customer->password = wp_hash_password($Order->Customer->password);
         }
         $Order->Customer->save();
         $Order->Billing->customer = $Order->Customer->id;
         $Order->Billing->card = substr($Order->Billing->card, -4);
         $Order->Billing->save();
         // Card data is truncated, switch the cart to normal mode
         if ($Shopp->Cart->secured() && is_shopp_secure()) {
             $Shopp->Cart->secured(false);
         }
         if (!empty($Order->Shipping->address)) {
             $Order->Shipping->customer = $Order->Customer->id;
             $Order->Shipping->save();
         }
         $Promos = array();
         foreach ($Shopp->Cart->data->PromosApplied as $promo) {
             $Promos[$promo->id] = $promo->name;
         }
         if ($Shopp->Cart->orderisfree()) {
             $orderisfree = true;
         } else {
             $orderisfree = false;
         }
         $Purchase = new Purchase();
         $Purchase->customer = $Order->Customer->id;
         $Purchase->billing = $Order->Billing->id;
         $Purchase->shipping = $Order->Shipping->id;
         $Purchase->copydata($Order->Customer);
         $Purchase->copydata($Order->Billing);
         $Purchase->copydata($Order->Shipping, 'ship');
         $Purchase->copydata($Shopp->Cart->data->Totals);
         $Purchase->data = $Order->data;
         $Purchase->promos = $Promos;
         $Purchase->freight = $Shopp->Cart->data->Totals->shipping;
         $Purchase->gateway = $gatewayname;
         $Purchase->transactionid = $transactionid;
         $Purchase->transtatus = "CHARGED";
         $Purchase->ip = $Shopp->Cart->ip;
         $Purchase->save();
         // echo "<pre>"; print_r($Purchase); echo "</pre>";
         foreach ($Shopp->Cart->contents as $Item) {
             $Purchased = new Purchased();
             $Purchased->copydata($Item);
             $Purchased->purchase = $Purchase->id;
             if (!empty($Purchased->download)) {
                 $Purchased->keygen();
             }
             $Purchased->save();
             if ($Item->inventory) {
                 $Item->unstock();
             }
         }
         if (SHOPP_DEBUG) {
             new ShoppError('Purchase ' . $Purchase->id . ' was successfully saved to the database.', false, SHOPP_DEBUG_ERR);
         }
     }
     // Skip post order if no Purchase ID exists
     if (empty($Purchase->id)) {
         return true;
     }
     // Empty cart on successful order
     $Shopp->Cart->unload();
     session_destroy();
     // Start new cart session
     $Shopp->Cart = new Cart();
     session_start();
     // Keep the user logged in or log them in if they are a new customer
     if ($Shopp->Cart->data->login || $authentication != "none") {
         $Shopp->Cart->loggedin($Order->Customer);
     }
     // Save the purchase ID for later lookup
     $Shopp->Cart->data->Purchase = new Purchase($Purchase->id);
     $Shopp->Cart->data->Purchase->load_purchased();
     // // $Shopp->Cart->save();
     // Allow other WordPress plugins access to Purchase data to extend
     // what Shopp does after a successful transaction
     do_action_ref_array('shopp_order_success', array(&$Shopp->Cart->data->Purchase));
     // Send email notifications
     // notification(addressee name, email, subject, email template, receipt template)
     $Purchase->notification("{$Purchase->firstname} {$Purchase->lastname}", $Purchase->email, __('Order Receipt', 'Shopp'));
     if ($Shopp->Settings->get('receipt_copy') == 1) {
         $Purchase->notification('', $Shopp->Settings->get('merchant_email'), __('New Order', 'Shopp'));
     }
     $ssl = true;
     // Test Mode will not require encrypted checkout
     if (strpos($gateway, "TestMode.php") !== false || isset($_GET['shopp_xco']) || $orderisfree || SHOPP_NOSSL) {
         $ssl = false;
     }
     shopp_redirect($Shopp->link('receipt', $ssl));
 }
 /**
  * securekey()
  * Generate the security key */
 function securekey()
 {
     global $Shopp;
     require_once ABSPATH . WPINC . '/pluggable.php';
     if (!is_shopp_secure()) {
         return false;
     }
     $expiration = time() + SHOPP_SESSION_TIMEOUT;
     if (defined('SECRET_AUTH_KEY') && SECRET_AUTH_KEY != '') {
         $key = SECRET_AUTH_KEY;
     } else {
         $key = md5(serialize($this->data) . time());
     }
     $content = hash_hmac('sha256', $this->session . '|' . $expiration, $key);
     if (version_compare(phpversion(), '5.2.0', 'ge')) {
         setcookie(SHOPP_SECURE_KEY, $content, 0, '/', '', true, true);
     } else {
         setcookie(SHOPP_SECURE_KEY, $content, 0, '/', '', true);
     }
     return $content;
 }