phpwordpresswoocommercepayment-gateway

WooCommerce wc-api returns wrong class


i have two Woocommerce payment gateway classes called "WC_banklink_seb" and "WC_banklink_swedbank" and the last one stopped working when updating Woocommerce 2.2 to 2.4

The integration and payment still work but the return URL that used wc-api does not.

When i use the "WC_banklink_swedbank" payment gateway and return from the payment provider to the URL http://my-domain.com/wc-api/WC_banklink_swedbank/ i get the following error:

Fatal error: invalid signature in .../wp-content/plugins/banklink_seb/banklink.php on line 304

The class "WC_banklink_swedbank" actualy resides in the folder .../wp-content/plugins/banklink_swedbank/

My questsion is why is the wc-api returning a class from another payment gateway? The only common thing between the classes WC_banklink_seb and WC_banklink_swedbank is that they both extend "WC_Payment_Gateway"

Both of the codes are appart from the class and plugin names pretty much identical because the "settings" are set over the adin panel.

What baffles me the worst is that when i disable the plugin of the class "WC_banklink_seb", the "WC_banklink_swedbank" starts working again?

<?php
/*
Plugin Name:banklink_swedbank
Plugin URI: 
Description:
Version: 1.0
License: GPL2
Text Domain: banklink_swedbank  
*/

if (!defined('ABSPATH')) exit; // Exit if accessed directly
if (!in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) return;

add_action('plugins_loaded', 'woocommerce_banklink_swedbank_init', 0);
function woocommerce_banklink_swedbank_init()
{
    add_action('init', 'translations_banklink_swedbank');
    function translations_banklink_swedbank()
    {
        load_plugin_textdomain('banklink_swedbank', FALSE, dirname(plugin_basename(__FILE__)) . '/languages/');
    }

    class WC_banklink_swedbank extends WC_Payment_Gateway
    {
        var $notify_url;

        function __construct()
        {
            global $woocommerce;

            $this->id = 'banklink_swedbank';
            $this->medthod_title = 'Pangalink (SEB)';
            $this->has_fields = false;
            $this->VK_CURR = 'EUR';
            $this->return_url = $this->get_return_url($order);
            $this->VK_RETURN = str_replace('https:', 'http:', home_url('/') . 'wc-api/WC_banklink_swedbank/');

            $this->init_form_fields();
            $this->init_settings();
            $this->icon = $this->settings['bank_logo'];
            $this->title = $this->settings['title'];
            $this->description = $this->settings['description'];
            $this->VK_SND_ID = $this->settings['VK_SND_ID'];
            $this->liveurl = $this->settings['liveurl'];
            $this->my_private_key = $this->settings['my_private_key'];
            $this->my_private_key_password = $this->settings['my_private_key_password'];
            $this->bank_certificate = $this->settings['bank_certificate'];
            $this->VK_ACC = $this->settings['VK_ACC'];
            $this->VK_NAME = $this->settings['VK_NAME'];
            $this->bank_name = $this->settings['bank_name'];
            $this->bank_charset = $this->settings['bank_charset'];
            $this->bank_charset_param = $this->settings['bank_charset_param'];
            $this->my_support_email = $this->settings['my_support_email'];


            add_action('woocommerce_update_options_payment_gateways_' . $this->id, array(&$this, 'process_admin_options'));
            add_action('woocommerce_receipt_banklink_swedbank', array(&$this, 'receipt_page'));

            add_action('woocommerce_api_wc_banklink_swedbank', array(&$this, 'check_bank_response'));
            add_action('valid_request', array($this, 'successful_request'));
            add_action('woocommerce_thankyou_banklink_swedbank', array(&$this, 'thankyou_page'));
        }

        function init_form_fields()
        {
            // removed from sample because not relevant to the problem
        }


        function admin_options()
        {
            // removed from sample because not relevant to the problem
        }

        function process_payment($order_id)
        {
            $order = new WC_Order($order_id);
            return array(
                'result' => 'success',
                'redirect' => add_query_arg('order', $order->id, add_query_arg('key', $order->order_key, get_permalink(woocommerce_get_page_id('pay'))))
            );
        }

        function receipt_page($order)
        {
            echo '<p>' . __('Pay through your bank', 'banklink_swedbank') . '</p>';
            echo $this->generate_bank_form($order);
        }

        function generate_bank_form($order_id)
        {
            global $woocommerce;
            $order = new WC_Order ($order_id);

            foreach ($order->get_items() as $item) {
                $item_names[] = $item['name'] . ' x ' . $item['qty'];
            }

            $mac_fields = array(
                'VK_SERVICE' => '1001',
                'VK_VERSION' => '008',
                'VK_SND_ID' => $this->to_bank_ch($this->VK_SND_ID),
                'VK_STAMP' => $this->to_bank_ch(str_replace('#', '', $order->get_order_number())),
                'VK_AMOUNT' => $this->to_bank_ch($order->get_total()),
                'VK_CURR' => $this->to_bank_ch($this->VK_CURR),
                'VK_ACC' => $this->to_bank_ch($this->VK_ACC),
                'VK_NAME' => $this->to_bank_ch($this->VK_NAME),
                'VK_REF' => $this->to_bank_ch($this->calculate_ref(str_replace('#', '', $order->get_order_number()))),
                'VK_MSG' => $this->to_bank_ch('Arve number: ' . $order->get_order_number()),
                'VK_RETURN' => $this->to_bank_ch($this->VK_RETURN));

            $p = $this->bank_charset_param;
            if ($p != '') {
                $mac_fields[$p] = $this->bank_charset;
            }

            $key = openssl_pkey_get_private(
                file_get_contents($this->my_private_key),
                $this->my_private_key_password);

            if (!openssl_sign($this->generate_mac_strings($mac_fields), $signature, $key)) {
                trigger_error("Unable to generate signature", E_USER_ERROR);
            }

            $mac_fields['VK_MAC'] = base64_encode($signature);
            $bank_args_array = array();
            foreach ($mac_fields as $key => $value) {
                $bank_args_array[] = '<input type="hidden" name="' . esc_attr($key) . '" value="' . esc_attr($value) . '" />';
            }

            return '<form action="' . esc_url($this->liveurl) . '" method="post" id="bank_payment_form" target="_top">
                ' . implode('', $bank_args_array) . '
                <input type="submit" class="button alt" id="submit_bank_payment_form" value="' . __('Pay', 'banklink_swedbank') . '" />
                <a class="button cancel" href="' . esc_url($order->get_cancel_order_url()) . '">' . __('Cancel order', 'banklink_swedbank') . '</a>
                </form>';
        }

        function check_bank_response()
        {
            @ob_clean();

            if (!empty($_REQUEST)) {
                header('HTTP/1.1 200 OK');
                do_action("valid_request", $_REQUEST);

            } else {
                wp_die("No response from the bank");
            }
        }

        function successful_request($posted)
        {

            $posted = stripslashes_deep($posted);
            $macFieldsBefore = array();

            foreach ((array)$posted as $f => $v) {
                if (substr($f, 0, 3) == 'VK_') {
                    $macFieldsBefore[$f] = $v;
                }
            }

            $p = $this->bank_charset_param;
            $bankCharset = '';
            if ($p != '') {
                $bankCharset = $macFieldsBefore[$p];
            }

            if ($bankCharset == '') {
                $bankCharset = 'iso-8859-1';
            }

            $macFields = array();
            foreach ($macFieldsBefore as $f => $v) {
                $macFields[$f] = $this->from_bank_ch($v, $bankCharset);
            }

            $key = openssl_pkey_get_public(file_get_contents($this->bank_certificate));

            if (!openssl_verify($this->generate_mac_strings($macFields), base64_decode($macFields['VK_MAC']), $key)) {
                trigger_error("Invalid signature", E_USER_ERROR);
            }

            $order_id = str_replace('#', '', $macFields['VK_STAMP']);
            $order = $this->get_order($order_id);

            if ($macFields['VK_SERVICE'] == '1901') {
                $macFields['message'] = __("Payment canceled!\n", 'banklink_swedbank');
                $macFields['status'] = 'pending';
                $macFields['return'] = $this->get_return_url($order);
            } elseif ($macFields['VK_SERVICE'] == '1902') {
                $macFields['message'] = sprintf(__("Payment unsuccessful!\nBank returned error %s!", 'banklink_swedbank'), $macFields('VK_ERROR_CODE'));
                $macFields['status'] = 'pending';
                $macFields['return'] = $this->get_return_url($order);
            } elseif ($macFields['VK_SERVICE'] == '1101') {
                if ($macFields['VK_REC_ID'] != $this->VK_SND_ID) {
                    $macFields['message'] = __("Payment unsuccessful!.\nBank returned unknown merchant ID!\n", 'banklink_swedbank');
                    $macFields['status'] = 'pending';
                    $macFields['return'] = $this->get_return_url($order);

                } elseif ($macFields['VK_AMOUNT'] != $order->get_total()) {
                    $macFields['message'] = __("Payd ammount and order ammount do not match!\nOrder has been set to on-hold.\nPlease contact us: ", 'banklink_swedbank') . $this->my_support_email . "\n";
                    $macFields['status'] = "on-hold";
                    $macFields['return'] = $this->get_return_url($order);
                } else {
                    $macFields['message'] = __("Payment recieved!\n", 'banklink_swedbank');
                    $macFields['status'] = "completed";
                    $macFields['return'] = $this->get_return_url($order);
                }
            } else {
                $macFields['message'] = __("Payment unsuccessful!\nUnknown reply: ", 'banklink_swedbank') . $macFields['VK_SERVICE'] . "\n";
                $macFields['status'] = 'pending';
                $macFields['return'] = $this->get_return_url($order);
            }

            if ($macFields['status'] == 'completed') {
                $order->add_order_note($macFields['message']);
                $order->payment_complete();
            } else {
                $order->update_status($macFields['status'], sprintf(__('Payment on-hold: %s', 'banklink_swedbank'), $macFields['message']));
                $order->add_order_note($macFields['message']);

            }

            wp_safe_redirect(add_query_arg('status', urlencode($macFields['status']), add_query_arg('msg', urlencode($macFields['message']), $macFields['return'])));
        }

        function thankyou_page()
        {
            $order = $this->get_order($_GET['order']);
            $color = $_GET['status'] != 'completed' ? 'orange' : 'green';
            $msg = $_GET['msg'];
            echo '<h2 style="color:' . $color . ';">' . $msg . '</h2>';
        }


        function get_order($order_id)
        {
            $order = new WC_Order($order_id);
            if (!isset($order->id)) {
                $order_id = woocommerce_get_order_id_by_order_key($order_key);
            }
            return $order;
        }

        function to_bank_ch($v)
        {
            $bankCharset = $this->bank_charset;
            if ($bankCharset != 'utf-8') {
                return mb_convert_encoding($v, $bankCharset, 'utf-8');
            } else {
                return $v;
            }
        }

        function from_bank_ch($v, $bankCharset)
        {
            return mb_convert_encoding($v, 'utf-8', $bankCharset);
        }

        function generate_mac_strings($mac_fields)
        {
            $n = new WC_banklink_swedbank();
            $VK_variableOrder = array(
                1001 => array(
                    'VK_SERVICE', 'VK_VERSION', 'VK_SND_ID',
                    'VK_STAMP', 'VK_AMOUNT', 'VK_CURR',
                    'VK_ACC', 'VK_NAME', 'VK_REF', 'VK_MSG'),
                1101 => array(
                    'VK_SERVICE', 'VK_VERSION', 'VK_SND_ID',
                    'VK_REC_ID', 'VK_STAMP', 'VK_T_NO', 'VK_AMOUNT', 'VK_CURR',
                    'VK_REC_ACC', 'VK_REC_NAME', 'VK_SND_ACC', 'VK_SND_NAME',
                    'VK_REF', 'VK_MSG', 'VK_T_DATE'),
                1901 => array(
                    'VK_SERVICE', 'VK_VERSION', 'VK_SND_ID',
                    'VK_REC_ID', 'VK_STAMP', 'VK_REF', 'VK_MSG'));

            $requestNum = $mac_fields['VK_SERVICE'];
            $data = '';

            foreach ((array)$VK_variableOrder[$requestNum] as $key) {
                $v = $mac_fields[$key];
                $l = ($n->bank_name == 'swedbank' ? mb_strlen($v, $n->bank_charset) : strlen($v));
                $data .= str_pad($l, 3, '0', STR_PAD_LEFT) . $v;
            }
            return $data;
        }

        function calculate_ref($nr)
        {
            $nr = (string)$nr;
            $kaal = array(7, 3, 1);
            $sl = $st = strlen($nr);
            $total = 0;
            while ($sl > 0 and substr($nr, --$sl, 1) >= '0') {
                $total += substr($nr, ($st - 1) - $sl, 1) * $kaal[($sl % 3)];
            }
            $kontrollnr = ((ceil(($total / 10)) * 10) - $total);
            return $nr . $kontrollnr;
        }


    }

    function woocommerce_add_banklink_swedbank_gateway($methods)
    {
        $methods[] = 'WC_banklink_swedbank';
        return $methods;
    }

    add_filter('woocommerce_payment_gateways', 'woocommerce_add_banklink_swedbank_gateway');
}

?>

Solution

  • The issue laid in the action name "valid_request" which was not unique. Both payment methods registered the same action so only the first one was really registered.

    add_action('valid_request', array($this, 'successful_request'));
    

    The name of the action should be replaced with a unique name, for example:

    add_action('valid_request_swedbank', array($this, 'successful_request'));
    

    Of course change the action name in the corresponding do_action()

    do_action( "valid_request_swedbank", $_REQUEST );