


PHP Modify zen-cart ordering and payment process to prevent missed orders_PHP tutorial
Anyone who has used zen-cart knows that the steps for placing an order in zen-cart are as follows (the expressions in [] are not necessary):
1. Shopping cart
2. [delivery method]
3. Payment method
4. Order confirmation (confirmation)
5. [Third-party website payment]
6. Order processing (checkout process) - This step is more important because the information in the shopping cart will be written into the order here
7. Order successful (checkout success)
There is no problem with this process under normal circumstances. However, in the process from step 5 to step 6, the user may think that the payment is successful and close the web page directly, or the user may not be able to jump to the checkout_process page normally due to network reasons. The consequences of this are very serious, because the order Cannot be created normally.
Based on the above analysis, we hope to change the process slightly, that is, the order has been created before payment, so that even if the payment cannot be redirected from the third-party payment website, we will not have the user fail to pay successfully. There are no orders in the background. The modified blueprint basically looks like this:
1. After confirming the order on the checkour_confirmation page, you will directly proccess and enter the checkour_success page, where you can enter the payment page. As shown in the picture below:
2. If the customer fails to pay at that time, they can also enter their own backend to pay for historical orders. As shown below:
Let’s take a look at how to implement the above functions step by step.
1. First we need to transform the existing payment module. It is necessary to add a field paynow_action_url to the payment method class to represent the page URL for payment. In addition, a function, paynow_button($order_id), needs to be added to obtain the parameter hidden field code of the payment form.
To add the paynow_action_url field, please add the following code at the end of the constructor of class payment:
if ( (zen_not_null($module)) && (in_array($module.'.php', $this->modules)) && (isset($GLOBALS[$module]->paynow_action_url)) ) {
$this->paynow_action_url = $GLOBALS[$module]->paynow_action_url;
}
To add the paynow_button($order_id) function, please add it to the payment class Add the following code after the last function:
function paynow_button($order_id){
if (is_array($this->modules)) {
if (is_object($GLOBALS[$this->selected_module])) {
return $GLOBALS[$this->selected_module]- >paynow_button($order_id);
}
}
}
2. Take the paypal payment method as an example to explain how to implement it. In order not to destroy the original code of paypal, we will make a copy of the paypal.php file, name it paypalsimple.php, and make appropriate modifications to the code inside. The code is as shown below. You can see that the specification of form_action_url is removed here and paynow_action_url is given. Because we hope that the user will directly enter the checkout_process after clicking "Confirm Order", so if form_action_url is not specified, then the form to confirm the order will be It is submitted directly to the checkout_process page, and paynow_action_url is the value of the previous form_action_url. The implementation of the paynow_button function is also very simple. Here we just cut the content of the original process_button() function, but we do not use the global $order variable, but use $order = new order($order_id) to re- An object constructed in preparation for displaying the pay now button in historical orders.
paypalsimple.php
/**
* @package paypalsimple payment module
* @copyright Copyright 2003-2006 Zen Cart Development Team
* @copyright Portions Copyright 2003 osCommerce
* @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
* @version $Id: paypalsimple.php 4960 2009-12-29 11:46:46Z gary $
*/
// ensure dependencies are loaded
include_once((IS_ADMIN_FLAG === true ? DIR_FS_CATALOG_MODULES : DIR_WS_MODULES) . 'payment/paypal/paypal_functions.php');
class paypalsimple {
var $code, $title, $description, $enabled;
// class constructor
function paypalsimple() {
global $order;
$this->code = 'paypalsimple';
$this->title = MODULE_PAYMENT_PAYPAL_SIMPLE_TEXT_TITLE;
if(IS_ADMIN_FLAG === true){
$this->title = MODULE_PAYMENT_PAYPAL_SIMPLE_TEXT_ADMIN_TITLE;
}
$this->description = MODULE_PAYMENT_PAYPAL_SIMPLE_TEXT_DESCRIPTION;
$this->sort_order = MODULE_PAYMENT_PAYPAL_SIMPLE_SORT_ORDER;
$this->enabled = ((MODULE_PAYMENT_PAYPAL_SIMPLE_STATUS == 'True') ? true : false);
if ((int)MODULE_PAYMENT_PAYPAL_SIMPLE_ORDER_STATUS_ID > 0) {
$this->order_status = MODULE_PAYMENT_PAYPAL_SIMPLE_ORDER_STATUS_ID;
}
$this->paynow_action_url = 'https://' . MODULE_PAYMENT_PAYPAL_SIMPLE_HANDLER;
if (is_object($order)) $this->update_status();
}
// class methods
function update_status() {
global $order, $db;
if ( ($this->enabled == true) && ((int)MODULE_PAYMENT_PAYPAL_SIMPLE_ZONE > 0) ) {
$check_flag = false;
$check = $db->Execute("select zone_id from " . TABLE_ZONES_TO_GEO_ZONES . " where geo_zone_id = '" . MODULE_PAYMENT_PAYPAL_SIMPLE_ZONE . "' and zone_country_id = '" . $order->billing['country']['id'] . "' order by zone_id");
while (!$check->EOF) {
if ($check->fields['zone_id'] $check_flag = true;
break;
} elseif ($check->fields['zone_id'] == $order->billing['zone_id']) {
$check_flag = true;
break;
}
$check->MoveNext();
}
if ($check_flag == false) {
$this->enabled = false;
}
}
}
function javascript_validation() {
return false;
}
function selection() {
$text = MODULE_PAYMENT_SIMPLE_PAYPAL_TEXT_CATALOG_LOGO.' '.MODULE_PAYMENT_PAYPAL_SIMPLE_TEXT_TITLE . '
' . MODULE_PAYMENT_PAYPAL_SIMPLE_ACCEPTANCE_MARK_TEXT . '
';
return array('id' => $this->code,
'module' => $text
);
}
function pre_confirmation_check() {
return false;
}
function confirmation() {
return false;
}
function process_button() {
return false;
}
function before_process() {
return false;
}
function after_process() {
return false;
}
function get_error() {
return false;
}
function check() {
global $db;
if (!isset($this->_check)) {
$check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_PAYPAL_SIMPLE_STATUS'");
$this->_check = $check_query->RecordCount();
}
return $this->_check;
}
function install() {
global $db;
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable PayPal-Simple Module', 'MODULE_PAYMENT_PAYPAL_SIMPLE_STATUS', 'True', 'Do you want to accept PayPal-Simple payments?', '6', '0', 'zen_cfg_select_option(array('True', 'False'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_PAYMENT_PAYPAL_SIMPLE_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '8', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Payment Zone', 'MODULE_PAYMENT_PAYPAL_SIMPLE_ZONE', '0', 'If a zone is selected, only enable this payment method for that zone.', '6', '2', 'zen_get_zone_class_title', 'zen_cfg_pull_down_zone_classes(', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Order Status', 'MODULE_PAYMENT_PAYPAL_SIMPLE_ORDER_STATUS_ID', '0', 'Set the status of orders made with this payment module to this value', '6', '0', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Mode for PayPal web services
Default:
www.paypal.com/cgi-bin/webscr
or
www.paypal.com/us/cgi-bin/webscr
or for the UK,
www.paypal.com/uk/cgi-bin/webscr
', 'MODULE_PAYMENT_PAYPAL_SIMPLE_HANDLER', 'www.paypal.com/cgi-bin/webscr', 'Choose the URL for PayPal live processing', '6', '73', '', now())"); }
function remove() {
global $db;
$db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
}
function keys() {
return array('MODULE_PAYMENT_PAYPAL_SIMPLE_STATUS','MODULE_PAYMENT_PAYPAL_SIMPLE_SORT_ORDER','MODULE_PAYMENT_PAYPAL_SIMPLE_ZONE','MODULE_PAYMENT_PAYPAL_SIMPLE_ORDER_STATUS_ID', 'MODULE_PAYMENT_PAYPAL_SIMPLE_HANDLER');
}
function paynow_button($order_id){
global $db, $order, $currencies, $currency;
require_once(DIR_WS_CLASSES . 'order.php');
$order = new order($order_id);
$options = array();
$optionsCore = array();
$optionsPhone = array();
$optionsShip = array();
$optionsLineItems = array();
$optionsAggregate = array();
$optionsTrans = array();
$buttonArray = array();
$this->totalsum = $order->info['total'];
// save the session stuff permanently in case paypal loses the session
$_SESSION['ppipn_key_to_remove'] = session_id();
$db->Execute("delete from " . TABLE_PAYPAL_SESSION . " where session_id = '" . zen_db_input($_SESSION['ppipn_key_to_remove']) . "'");
$sql = "insert into " . TABLE_PAYPAL_SESSION . " (session_id, saved_session, expiry) values (
'" . zen_db_input($_SESSION['ppipn_key_to_remove']) . "',
'" . base64_encode(serialize($_SESSION)) . "',
'" . (time() + (1*60*60*24*2)) . "')";
$db->Execute($sql);
$my_currency = select_pp_currency();
$this->transaction_currency = $my_currency;
$this->transaction_amount = ($this->totalsum * $currencies->get_value($my_currency));
$telephone = preg_replace('/D/', '', $order->customer['telephone']);
if ($telephone != '') {
$optionsPhone['H_PhoneNumber'] = $telephone;
if (in_array($order->customer['country']['iso_code_2'], array('US','CA'))) {
$optionsPhone['night_phone_a'] = substr($telephone,0,3);
$optionsPhone['night_phone_b'] = substr($telephone,3,3);
$optionsPhone['night_phone_c'] = substr($telephone,6,4);
$optionsPhone['day_phone_a'] = substr($telephone,0,3);
$optionsPhone['day_phone_b'] = substr($telephone,3,3);
$optionsPhone['day_phone_c'] = substr($telephone,6,4);
} else {
$optionsPhone['night_phone_b'] = $telephone;
$optionsPhone['day_phone_b'] = $telephone;
}
}
$optionsCore = array(
'charset' => CHARSET,
'lc' => $order->customer['country']['iso_code_2'],
'page_style' => MODULE_PAYMENT_PAYPAL_PAGE_STYLE,
'custom' => zen_session_name() . '=' . zen_session_id(),
'business' => MODULE_PAYMENT_PAYPAL_BUSINESS_ID,
'return' => zen_href_link(FILENAME_PAY_SUCCESS, 'referer=paypal', 'SSL'),
'cancel_return' => zen_href_link(FILENAME_PAY_FAILED, '', 'SSL'),
'shopping_url' => zen_href_link(FILENAME_SHOPPING_CART, '', 'SSL'),
'notify_url' => zen_href_link('ipn_main_handler.php', '', 'SSL',false,false,true),
'redirect_cmd' => '_xclick',
'rm' => 2,
'bn' => 'zencart',
'mrb' => 'R-6C7952342H795591R',
'pal' => '9E82WJBKKGPLQ',
);
$optionsCust = array(
'first_name' => replace_accents($order->customer['firstname']),
'last_name' => replace_accents($order->customer['lastname']),
'address1' => replace_accents($order->customer['street_address']),
'city' => replace_accents($order->customer['city']),
'state' => zen_get_zone_code($order->customer['country']['id'], $order->customer['zone_id'], $order->customer['zone_id']),
'zip' => $order->customer['postcode'],
'country' => $order->customer['country']['iso_code_2'],
'email' => $order->customer['email_address'],
);
if ($order->customer['suburb'] != '') $optionsCust['address2'] = $order->customer['suburb'];
if (MODULE_PAYMENT_PAYPAL_ADDRESS_REQUIRED == 2) $optionsCust = array(
'address_name' => replace_accents($order->customer['firstname'] . ' ' . $order->customer['lastname']),
'address_street' => replace_accents($order->customer['street_address']),
'address_city' => replace_accents($order->customer['city']),
'address_state' => zen_get_zone_code($order->customer['country']['id'], $order->customer['zone_id'], $order->customer['zone_id']),
'address_zip' => $order->customer['postcode'],
'address_country' => $order->customer['country']['title'],
'address_country_code' => $order->customer['country']['iso_code_2'],
'payer_email' => $order->customer['email_address'],
);
$optionsShip = array(
//'address_override' => MODULE_PAYMENT_PAYPAL_ADDRESS_OVERRIDE,
'no_shipping' => MODULE_PAYMENT_PAYPAL_ADDRESS_REQUIRED,
);
if (MODULE_PAYMENT_PAYPAL_DETAILED_CART == 'Yes') $optionsLineItems = ipn_getLineItemDetails();
if (sizeof($optionsLineItems) > 0) {
$optionsLineItems['cmd'] = '_cart';
// $optionsLineItems['num_cart_items'] = sizeof($order->products);
if (isset($optionsLineItems['shipping'])) {
$optionsLineItems['shipping_1'] = $optionsLineItems['shipping'];
unset($optionsLineItems['shipping']);
}
if (isset($optionsLineItems['handling'])) {
$optionsLineItems['handling_1'] = $optionsLineItems['handling'];
unset($optionsLineItems['handling']);
}
unset($optionsLineItems['subtotal']);
// if line-item details couldn't be kept due to calculation mismatches or discounts etc, default to aggregate mode
if (!isset($optionsLineItems['item_name_1'])) $optionsLineItems = array();
//if ($optionsLineItems['amount'] != $this->transaction_amount) $optionsLineItems = array();
ipn_debug_email('Line Item Details (if blank, this means there was a data mismatch, and thus bypassed): ' . "n" . print_r($optionsLineItems, true));
}
$products_name_display = "";
/*
for ($i=0, $n=sizeof($order->products); $iif(i > 0) {
$products_name_display.= ', ';
}
$products_name_display.= $order->products[$i]['name']. '('. $order->products[$i]['qty'] .','.$order->products[$i]['dhisys_web_order_number'].')';
}*/
$optionsAggregate = array(
'cmd' => '_ext-enter',
'item_name' => $products_name_display,
'item_number' => $order_id,
'num_cart_items' => sizeof($order->products),
'amount' => number_format($this->transaction_amount, $currencies->get_decimal_places($my_currency)),
'shipping' => '0.00',
);
if (MODULE_PAYMENT_PAYPAL_TAX_OVERRIDE == 'true') $optionsAggregate['tax'] = '0.00';
if (MODULE_PAYMENT_PAYPAL_TAX_OVERRIDE == 'true') $optionsAggregate['tax_cart'] = '0.00';
$optionsTrans = array(
'upload' => (int)(sizeof($order->products) > 0),
'currency_code' => $my_currency,
// 'paypal_order_id' => $paypal_order_id,
//'no_note' => '1',
//'invoice' => '',
);
// if line-item info is invalid, use aggregate:
if (sizeof($optionsLineItems) > 0) $optionsAggregate = $optionsLineItems;
// prepare submission
$options = array_merge($optionsCore, $optionsCust, $optionsPhone, $optionsShip, $optionsTrans, $optionsAggregate);
ipn_debug_email('Keys for submission: ' . print_r($options, true));
if(sizeof($order->products) > 0){
$options['cmd'] = '_cart';
for ($i=0, $n=sizeof($order->products); $i$options['item_name_'. (string)($i+1)] = $order->products[$i]['name'];
$options['item_number_'. (string)($i+1)] = $order->products[$i]['dhisys_web_order_number'];
$options['amount_'. (string)($i+1)] = number_format((float)$order->products[$i]['final_price'],2);
$options['quantity_'. (string)($i+1)] = $order->products[$i]['qty'];
}
}
// build the button fields
foreach ($options as $name => $value) {
// remove quotation marks
$value = str_replace('"', '', $value);
// check for invalid chars
if (preg_match('/[^a-zA-Z_0-9]/', $name)) {
ipn_debug_email('datacheck - ABORTING - preg_match found invalid submission key: ' . $name . ' (' . $value . ')');
break;
}
// do we need special handling for & and = symbols?
//if (strpos($value, '&') !== false || strpos($value, '=') !== false) $value = urlencode($value);
$buttonArray[] = zen_draw_hidden_field($name, $value);
}
$_SESSION['paypal_transaction_info'] = array($this->transaction_amount, $this->transaction_currency);
$process_button_string = implode("n", $buttonArray) . "n";
return $process_button_string;
}
}
?>
3. 在checkout_success页面中显示pay now按钮。打开文件"includes/modules/pages/checkout_success/header.php",在文件的末尾添加下面的代码(如果你已经掌握zen-cart中的通知者/观察者模式,并且又不想破坏zen-cart核心代码的话,也可以创建一个观察类来监听NOTIFY_HEADER_END_CHECKOUT_SUCCESS来实现)。
require_once(DIR_WS_CLASSES . 'order.php');
require_once(DIR_WS_CLASSES . 'payment.php');
$payment_modules = new payment($orders->fields['payment_module_code']);
打开文件"includes/modules/templates/template_default/templates/tpl_checkout_success_default.php",并在适当的位置加上如下的代码,这里对订单的状态进行了一个判断,当只有订单的状态在未付款状态,才显示该按钮,
//&& $orders->fields['orders_status'] == '1'
if(isset($payment_modules->paynow_action_url) && $payment_modules->paynow_action_url != ''&& $orders->fields['orders_status'] == '1'){
echo('');
}
?>
4. Display pay now button in historical orders. There are three pages that need to display the pay now button: account, account_history, and account_history_info. The implementation here is similar to the implementation of the checkout_success page, except that the parameters of the function paynow_button passed to $payment_modules are different, so I will not go into details here.
Summary:
After the above modifications, our process is as follows:
1. Shopping cart (shopping cart)
2. [delivery method]
3. Payment method ( payment method)
4. Order confirmation (confirmation)
5. Order processing (checkout process)
6. Order successful (checkout success)
7. [Third-party website payment]
Because everything from order confirmation to order processing is completed on our own website, and the order already exists before entering the payment website, this way there will be no dropped orders.

The article explains how to create, implement, and use interfaces in PHP, focusing on their benefits for code organization and maintainability.

The article discusses the differences between crypt() and password_hash() in PHP for password hashing, focusing on their implementation, security, and suitability for modern web applications.

Article discusses preventing Cross-Site Scripting (XSS) in PHP through input validation, output encoding, and using tools like OWASP ESAPI and HTML Purifier.

Autoloading in PHP automatically loads class files when needed, improving performance by reducing memory use and enhancing code organization. Best practices include using PSR-4 and organizing code effectively.

PHP streams unify handling of resources like files, network sockets, and compression formats via a consistent API, abstracting complexity and enhancing code flexibility and efficiency.

The article discusses managing file upload sizes in PHP, focusing on the default limit of 2MB and how to increase it by modifying php.ini settings.

The article discusses nullable types in PHP, introduced in PHP 7.1, allowing variables or parameters to be either a specified type or null. It highlights benefits like improved readability, type safety, and explicit intent, and explains how to declar

The article discusses the differences between unset() and unlink() functions in programming, focusing on their purposes and use cases. Unset() removes variables from memory, while unlink() deletes files from the filesystem. Both are crucial for effec


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

SublimeText3 Chinese version
Chinese version, very easy to use

EditPlus Chinese cracked version
Small size, syntax highlighting, does not support code prompt function

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

WebStorm Mac version
Useful JavaScript development tools

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool
