sage_pay_server::before_process()   F
last analyzed

Complexity

Conditions 29
Paths 1348

Size

Total Lines 158
Code Lines 100

Duplication

Lines 33
Ratio 20.89 %

Importance

Changes 0
Metric Value
cc 29
eloc 100
nc 1348
nop 0
dl 33
loc 158
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
  * osCommerce Online Merchant
4
  *
5
  * @copyright (c) 2016 osCommerce; https://www.oscommerce.com
6
  * @license MIT; https://www.oscommerce.com/license/mit.txt
7
  */
8
9
  use OSC\OM\Hash;
10
  use OSC\OM\HTML;
11
  use OSC\OM\HTTP;
12
  use OSC\OM\Mail;
13
  use OSC\OM\OSCOM;
14
  use OSC\OM\Registry;
15
16
  class sage_pay_server {
17
    var $code, $title, $description, $enabled;
18
19 View Code Duplication
    function __construct() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
20
      global $PHP_SELF, $order;
21
22
      $this->signature = 'sage_pay|sage_pay_server|2.1|2.3';
0 ignored issues
show
Bug introduced by
The property signature does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
23
      $this->api_version = '3.00';
0 ignored issues
show
Bug introduced by
The property api_version does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
24
25
      $this->code = 'sage_pay_server';
26
      $this->title = OSCOM::getDef('module_payment_sage_pay_server_text_title');
27
      $this->public_title = OSCOM::getDef('module_payment_sage_pay_server_text_public_title');
0 ignored issues
show
Bug introduced by
The property public_title does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
28
      $this->description = OSCOM::getDef('module_payment_sage_pay_server_text_description');
29
      $this->sort_order = defined('MODULE_PAYMENT_SAGE_PAY_SERVER_SORT_ORDER') ? MODULE_PAYMENT_SAGE_PAY_SERVER_SORT_ORDER : 0;
0 ignored issues
show
Bug introduced by
The property sort_order does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
30
      $this->enabled = defined('MODULE_PAYMENT_SAGE_PAY_SERVER_STATUS') && (MODULE_PAYMENT_SAGE_PAY_SERVER_STATUS == 'True') ? true : false;
31
      $this->order_status = defined('MODULE_PAYMENT_SAGE_PAY_SERVER_ORDER_STATUS_ID') && ((int)MODULE_PAYMENT_SAGE_PAY_SERVER_ORDER_STATUS_ID > 0) ? (int)MODULE_PAYMENT_SAGE_PAY_SERVER_ORDER_STATUS_ID : 0;
0 ignored issues
show
Bug introduced by
The property order_status does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
32
33
      if ( defined('MODULE_PAYMENT_SAGE_PAY_SERVER_STATUS') ) {
34
        if ( MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_SERVER == 'Test' ) {
35
          $this->title .= ' [Test]';
36
          $this->public_title .= ' (' . $this->code . '; Test)';
37
        }
38
39
        $this->description .= $this->getTestLinkInfo();
40
      }
41
42
      if ( !function_exists('curl_init') ) {
43
        $this->description = '<div class="secWarning">' . OSCOM::getDef('module_payment_sage_pay_server_error_admin_curl') . '</div>' . $this->description;
44
45
        $this->enabled = false;
46
      }
47
48
      if ( $this->enabled === true ) {
49
        if ( !tep_not_null(MODULE_PAYMENT_SAGE_PAY_SERVER_VENDOR_LOGIN_NAME) ) {
50
          $this->description = '<div class="secWarning">' . OSCOM::getDef('module_payment_sage_pay_server_error_admin_configuration') . '</div>' . $this->description;
51
52
          $this->enabled = false;
53
        }
54
      }
55
56
      if ( $this->enabled === true ) {
57
        if ( isset($order) && is_object($order) ) {
58
          $this->update_status();
59
        }
60
      }
61
62
      if ( defined('FILENAME_MODULES') && (basename($PHP_SELF) == 'modules.php') && isset($_GET['action']) && ($_GET['action'] == 'install') && isset($_GET['subaction']) && ($_GET['subaction'] == 'conntest') ) {
63
        echo $this->getTestConnectionResult();
64
        exit;
65
      }
66
    }
67
68 View Code Duplication
    function update_status() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
69
      global $order;
70
71
      $OSCOM_Db = Registry::get('Db');
72
73
      if ( ($this->enabled == true) && ((int)MODULE_PAYMENT_SAGE_PAY_SERVER_ZONE > 0) ) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
74
        $check_flag = false;
75
        $Qcheck = $OSCOM_Db->get('zones_to_geo_zones', 'zone_id', ['geo_zone_id' => MODULE_PAYMENT_SAGE_PAY_SERVER_ZONE, 'zone_country_id' => $order->billing['country']['id']], 'zone_id');
76
        while ($Qcheck->fetch()) {
77
          if ($Qcheck->valueInt('zone_id') < 1) {
78
            $check_flag = true;
79
            break;
80
          } elseif ($Qcheck->valueInt('zone_id') == $order->billing['zone_id']) {
81
            $check_flag = true;
82
            break;
83
          }
84
        }
85
86
        if ($check_flag == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
87
          $this->enabled = false;
88
        }
89
      }
90
    }
91
92
    function javascript_validation() {
93
      return false;
94
    }
95
96
    function selection() {
97
      return array('id' => $this->code,
98
                   'module' => $this->public_title);
99
    }
100
101
    function pre_confirmation_check() {
102
      return false;
103
    }
104
105
    function confirmation() {
106
      return false;
107
    }
108
109
    function process_button() {
110
      return false;
111
    }
112
113
    function before_process() {
114
      global $sagepay_server_transaction_details, $order, $order_totals;
115
116
      $OSCOM_Db = Registry::get('Db');
117
118
      $sagepay_server_transaction_details = null;
119
120
      $error = null;
121
122
      if (isset($_GET['check']) && ($_GET['check'] == 'PROCESS')) {
123
        if ( isset($_GET['skcode']) && isset($_SESSION['sagepay_server_skey_code']) && ($_GET['skcode'] == $_SESSION['sagepay_server_skey_code']) ) {
124
          $skcode = HTML::sanitize($_GET['skcode']);
125
126
          $Qsp = $OSCOM_Db->get('sagepay_server_securitykeys', ['verified', 'transaction_details'], ['code' => $skcode], null, 1);
127
128
          if ($Qsp->fetch() !== false) {
129
            unset($_SESSION['sagepay_server_skey_code']);
130
131
            $OSCOM_Db->delete('sagepay_server_securitykeys', ['code' => $skcode]);
132
133
            if ( $Qsp->value('verified') == '1' ) {
134
              $sagepay_server_transaction_details = $Qsp->value('transaction_details');
135
136
              return true;
137
            }
138
          }
139
        }
140
      } else {
141
        if ( !isset($_SESSION['sagepay_server_skey_code']) ) {
142
          $_SESSION['sagepay_server_skey_code'] = Hash::getRandomString(16);
143
        }
144
145
        $params = array('VPSProtocol' => $this->api_version,
146
                        'ReferrerID' => 'C74D7B82-E9EB-4FBD-93DB-76F0F551C802',
147
                        'Vendor' => substr(MODULE_PAYMENT_SAGE_PAY_SERVER_VENDOR_LOGIN_NAME, 0, 15),
148
                        'VendorTxCode' => substr(date('YmdHis') . '-' . $_SESSION['customer_id'] . '-' . $_SESSION['cartID'], 0, 40),
149
                        'Amount' => $this->format_raw($order->info['total']),
150
                        'Currency' => $_SESSION['currency'],
151
                        'Description' => substr(STORE_NAME, 0, 100),
152
                        'NotificationURL' => $this->formatURL(OSCOM::link('ext/modules/payment/sage_pay/server.php', 'check=SERVER&skcode=' . $_SESSION['sagepay_server_skey_code'], false)),
153
                        'BillingSurname' => substr($order->billing['lastname'], 0, 20),
154
                        'BillingFirstnames' => substr($order->billing['firstname'], 0, 20),
155
                        'BillingAddress1' => substr($order->billing['street_address'], 0, 100),
156
                        'BillingCity' => substr($order->billing['city'], 0, 40),
157
                        'BillingPostCode' => substr($order->billing['postcode'], 0, 10),
158
                        'BillingCountry' => $order->billing['country']['iso_code_2'],
159
                        'BillingPhone' => substr($order->customer['telephone'], 0, 20),
160
                        'DeliverySurname' => substr($order->delivery['lastname'], 0, 20),
161
                        'DeliveryFirstnames' => substr($order->delivery['firstname'], 0, 20),
162
                        'DeliveryAddress1' => substr($order->delivery['street_address'], 0, 100),
163
                        'DeliveryCity' => substr($order->delivery['city'], 0, 40),
164
                        'DeliveryPostCode' => substr($order->delivery['postcode'], 0, 10),
165
                        'DeliveryCountry' => $order->delivery['country']['iso_code_2'],
166
                        'DeliveryPhone' => substr($order->customer['telephone'], 0, 20),
167
                        'CustomerEMail' => substr($order->customer['email_address'], 0, 255),
168
                        'Apply3DSecure' => '0');
169
170
        $ip_address = HTTP::getIpAddress();
171
172
        if ( (ip2long($ip_address) != -1) && (ip2long($ip_address) != false) ) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing ip2long($ip_address) of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
173
          $params['ClientIPAddress']= $ip_address;
174
        }
175
176 View Code Duplication
        if ( MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_METHOD == 'Payment' ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177
          $params['TxType'] = 'PAYMENT';
178
        } elseif ( MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_METHOD == 'Deferred' ) {
179
          $params['TxType'] = 'DEFERRED';
180
        } else {
181
          $params['TxType'] = 'AUTHENTICATE';
182
        }
183
184 View Code Duplication
        if ($params['BillingCountry'] == 'US') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
185
          $params['BillingState'] = tep_get_zone_code($order->billing['country']['id'], $order->billing['zone_id'], '');
186
        }
187
188 View Code Duplication
        if ($params['DeliveryCountry'] == 'US') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
189
          $params['DeliveryState'] = tep_get_zone_code($order->delivery['country']['id'], $order->delivery['zone_id'], '');
190
        }
191
192
        if ( MODULE_PAYMENT_SAGE_PAY_SERVER_PROFILE_PAGE != 'Normal' ) {
193
          $params['Profile'] = 'LOW';
194
        }
195
196
        $contents = array();
197
198 View Code Duplication
        foreach ($order->products as $product) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
199
          $product_name = $product['name'];
200
201
          if (isset($product['attributes'])) {
202
            foreach ($product['attributes'] as $att) {
203
              $product_name .= '; ' . $att['option'] . '=' . $att['value'];
204
            }
205
          }
206
207
          $contents[] = str_replace(array(':', "\n", "\r", '&'), '', $product_name) . ':' . $product['qty'] . ':' . $this->format_raw($product['final_price']) . ':' . $this->format_raw(($product['tax'] / 100) * $product['final_price']) . ':' . $this->format_raw((($product['tax'] / 100) * $product['final_price']) + $product['final_price']) . ':' . $this->format_raw(((($product['tax'] / 100) * $product['final_price']) + $product['final_price']) * $product['qty']);
208
        }
209
210 View Code Duplication
        foreach ($order_totals as $ot) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
211
          $contents[] = str_replace(array(':', "\n", "\r", '&'), '', strip_tags($ot['title'])) . ':---:---:---:---:' . $this->format_raw($ot['value']);
212
        }
213
214
        $params['Basket'] = substr(sizeof($contents) . ':' . implode(':', $contents), 0, 7500);
215
216
        $post_string = '';
217
218
        foreach ($params as $key => $value) {
219
          $post_string .= $key . '=' . urlencode(trim($value)) . '&';
220
        }
221
222
        if ( MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_SERVER == 'Live' ) {
223
          $gateway_url = 'https://live.sagepay.com/gateway/service/vspserver-register.vsp';
224
        } else {
225
          $gateway_url = 'https://test.sagepay.com/gateway/service/vspserver-register.vsp';
226
        }
227
228
        $transaction_response = $this->sendTransactionToGateway($gateway_url, $post_string);
229
230
        $string_array = explode(chr(10), $transaction_response);
231
        $return = array();
232
233 View Code Duplication
        foreach ($string_array as $string) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
234
          if (strpos($string, '=') != false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($string, '=') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
235
            $parts = explode('=', $string, 2);
236
            $return[trim($parts[0])] = trim($parts[1]);
237
          }
238
        }
239
240
        if ($return['Status'] == 'OK') {
241
          $Qsp = $OSCOM_Db->get('sagepay_server_securitykeys', ['id', 'securitykey'], ['code' => $_SESSION['sagepay_server_skey_code']], null, 1);
242
243
          if ($Qsp->fetch() !== false) {
244
            if ( $Qsp->value('securitykey') != $return['SecurityKey'] ) {
245
              $OSCOM_Db->save('sagepay_server_securitykeys', ['securitykey' => $return['SecurityKey'], 'date_added' => 'now()'], ['id' => $Qsp->valueInt('id')]);
246
            }
247
          } else {
248
            $OSCOM_Db->save('sagepay_server_securitykeys', [
249
              'code' => $_SESSION['sagepay_server_skey_code'],
250
              'securitykey' => $return['SecurityKey'],
251
              'date_added' => 'now()'
252
            ]);
253
          }
254
255
          if ( MODULE_PAYMENT_SAGE_PAY_SERVER_PROFILE_PAGE == 'Normal' ) {
256
            HTTP::redirect($return['NextURL']);
257
          } else {
258
            $_SESSION['sage_pay_server_nexturl'] = $return['NextURL'];
259
260
            OSCOM::redirect('ext/modules/payment/sage_pay/checkout.php');
261
          }
262
        } else {
263
          $error = $this->getErrorMessageNumber($return['StatusDetail']);
264
265
          $this->sendDebugEmail($return);
266
        }
267
      }
268
269
      OSCOM::redirect('checkout_payment.php', 'payment_error=' . $this->code . (tep_not_null($error) ? '&error=' . $error : ''));
270
    }
271
272
    function after_process() {
273
      global $insert_id, $sagepay_server_transaction_details;
274
275
      $OSCOM_Db = Registry::get('Db');
276
277
      $sql_data_array = array('orders_id' => $insert_id,
278
                              'orders_status_id' => DEFAULT_ORDERS_STATUS_ID,
279
                              'date_added' => 'now()',
280
                              'customer_notified' => '0',
281
                              'comments' => trim($sagepay_server_transaction_details));
282
283
      $OSCOM_Db->save('orders_status_history', $sql_data_array);
284
285
      if ( MODULE_PAYMENT_SAGE_PAY_SERVER_PROFILE_PAGE == 'Low' ) {
286
        $_SESSION['cart']->reset(true);
287
288
// unregister session variables used during checkout
289
        unset($_SESSION['sendto']);
290
        unset($_SESSION['billto']);
291
        unset($_SESSION['shipping']);
292
        unset($_SESSION['payment']);
293
        unset($_SESSION['comments']);
294
295
        unset($_SESSION['sage_pay_server_nexturl']);
296
297
        OSCOM::redirect('ext/modules/payment/sage_pay/redirect.php');
298
      }
299
    }
300
301
    function get_error() {
302
      $message = OSCOM::getDef('module_payment_sage_pay_server_error_general');
303
304
      $error_number = null;
305
306
      if ( isset($_GET['error']) && is_numeric($_GET['error']) && $this->errorMessageNumberExists($_GET['error']) ) {
307
        $error_number = $_GET['error'];
308
      }
309
310 View Code Duplication
      if ( isset($error_number) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
311
// don't show an error message for user cancelled/aborted transactions
312
        if ( $error_number == '2013' ) {
313
          return false;
314
        }
315
316
        $message = $this->getErrorMessage($error_number) . ' ' . OSCOM::getDef('module_payment_sage_pay_server_error_general');
317
      }
318
319
      $error = array('title' => OSCOM::getDef('module_payment_sage_pay_server_error_title'),
320
                     'error' => $message);
321
322
      return $error;
323
    }
324
325
    function check() {
326
      return defined('MODULE_PAYMENT_SAGE_PAY_SERVER_STATUS');
327
    }
328
329 View Code Duplication
    function install($parameter = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
330
      $OSCOM_Db = Registry::get('Db');
331
332
      $params = $this->getParams();
333
334
      if (isset($parameter)) {
335
        if (isset($params[$parameter])) {
336
          $params = array($parameter => $params[$parameter]);
337
        } else {
338
          $params = array();
339
        }
340
      }
341
342
      foreach ($params as $key => $data) {
343
        $sql_data_array = array('configuration_title' => $data['title'],
344
                                'configuration_key' => $key,
345
                                'configuration_value' => (isset($data['value']) ? $data['value'] : ''),
346
                                'configuration_description' => $data['desc'],
347
                                'configuration_group_id' => '6',
348
                                'sort_order' => '0',
349
                                'date_added' => 'now()');
350
351
        if (isset($data['set_func'])) {
352
          $sql_data_array['set_function'] = $data['set_func'];
353
        }
354
355
        if (isset($data['use_func'])) {
356
          $sql_data_array['use_function'] = $data['use_func'];
357
        }
358
359
        $OSCOM_Db->save('configuration', $sql_data_array);
360
      }
361
    }
362
363
    function remove() {
364
      return Registry::get('Db')->exec('delete from :table_configuration where configuration_key in ("' . implode('", "', $this->keys()) . '")');
365
    }
366
367 View Code Duplication
    function keys() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
368
      $keys = array_keys($this->getParams());
369
370
      if ($this->check()) {
371
        foreach ($keys as $key) {
372
          if (!defined($key)) {
373
            $this->install($key);
374
          }
375
        }
376
      }
377
378
      return $keys;
379
    }
380
381
    function getParams() {
382
      $OSCOM_Db = Registry::get('Db');
383
384
      $Qcheck = $OSCOM_Db->query('show tables like "sagepay_server_securitykeys"');
385
386
      if ($Qcheck->fetch() === false) {
387
        $sql = <<<EOD
388
CREATE TABLE sagepay_server_securitykeys (
389
  id int NOT NULL auto_increment,
390
  code char(16) NOT NULL,
391
  securitykey char(10) NOT NULL,
392
  date_added datetime NOT NULL,
393
  verified char(1) DEFAULT 0,
394
  transaction_details text,
395
  PRIMARY KEY (id),
396
  KEY idx_sagepay_server_securitykeys_code (code),
397
  KEY idx_sagepay_server_securitykeys_securitykey (securitykey)
398
);
399
EOD;
400
401
        $OSCOM_Db->exec($sql);
402
      }
403
404 View Code Duplication
      if (!defined('MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_ORDER_STATUS_ID')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
405
        $Qcheck = $OSCOM_Db->get('orders_status', 'orders_status_id', ['orders_status_name' => 'Sage Pay [Transactions]'], null, 1);
406
407
        if ($Qcheck->fetch() === false) {
408
          $Qstatus = $OSCOM_Db->get('orders_status', 'max(orders_status_id) as status_id');
409
410
          $status_id = $Qstatus->valueInt('status_id') + 1;
411
412
          $languages = tep_get_languages();
413
414
          foreach ($languages as $lang) {
415
            $OSCOM_Db->save('orders_status', [
416
              'orders_status_id' => $status_id,
417
              'language_id' => $lang['id'],
418
              'orders_status_name' => 'Sage Pay [Transactions]',
419
              'public_flag' => 0,
420
              'downloads_flag' => 0
421
            ]);
422
          }
423
        } else {
424
          $status_id = $Qcheck->valueInt('orders_status_id');
425
        }
426
      } else {
427
        $status_id = MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_ORDER_STATUS_ID;
428
      }
429
430
      $params = array('MODULE_PAYMENT_SAGE_PAY_SERVER_STATUS' => array('title' => 'Enable Sage Pay Server Module',
431
                                                                       'desc' => 'Do you want to accept Sage Pay Server payments?',
432
                                                                       'value' => 'True',
433
                                                                       'set_func' => 'tep_cfg_select_option(array(\'True\', \'False\'), '),
434
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_VENDOR_LOGIN_NAME' => array('title' => 'Vendor Login Name',
435
                                                                                  'desc' => 'The vendor login name to connect to the gateway with.'),
436
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_PROFILE_PAGE' => array('title' => 'Profile Payment Page',
437
                                                                             'desc' => 'Profile page to use for the payment page, Normal is a full redirect to Sage Pay and Low loads through an iframe.',
438
                                                                             'value' => 'Normal',
439
                                                                             'set_func' => 'tep_cfg_select_option(array(\'Normal\', \'Low\'), '),
440
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_METHOD' => array('title' => 'Transaction Method',
441
                                                                                   'desc' => 'The processing method to use for each transaction.',
442
                                                                                   'value' => 'Authenticate',
443
                                                                                   'set_func' => 'tep_cfg_select_option(array(\'Authenticate\', \'Deferred\', \'Payment\'), '),
444
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_ORDER_STATUS_ID' => array('title' => 'Set Order Status',
445
                                                                                'desc' => 'Set the status of orders made with this payment module to this value',
446
                                                                                'value' => '0',
447
                                                                                'use_func' => 'tep_get_order_status_name',
448
                                                                                'set_func' => 'tep_cfg_pull_down_order_statuses('),
449
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_ORDER_STATUS_ID' => array('title' => 'Transaction Order Status',
450
                                                                                            'desc' => 'Include transaction information in this order status level',
451
                                                                                            'value' => $status_id,
452
                                                                                            'set_func' => 'tep_cfg_pull_down_order_statuses(',
453
                                                                                            'use_func' => 'tep_get_order_status_name'),
454
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_ZONE' => array('title' => 'Payment Zone',
455
                                                                     'desc' => 'If a zone is selected, only enable this payment method for that zone.',
456
                                                                     'value' => '0',
457
                                                                     'use_func' => 'tep_get_zone_class_title',
458
                                                                     'set_func' => 'tep_cfg_pull_down_zone_classes('),
459
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_SERVER' => array('title' => 'Transaction Server',
460
                                                                                   'desc' => 'Perform transactions on the production server or on the testing server.',
461
                                                                                   'value' => 'Live',
462
                                                                                   'set_func' => 'tep_cfg_select_option(array(\'Live\', \'Test\'), '),
463
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_VERIFY_SSL' => array('title' => 'Verify SSL Certificate',
464
                                                                           'desc' => 'Verify transaction server SSL certificate on connection?',
465
                                                                           'value' => 'True',
466
                                                                           'set_func' => 'tep_cfg_select_option(array(\'True\', \'False\'), '),
467
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_PROXY' => array('title' => 'Proxy Server',
468
                                                                      'desc' => 'Send API requests through this proxy server. (host:port, eg: 123.45.67.89:8080 or proxy.example.com:8080)'),
469
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_DEBUG_EMAIL' => array('title' => 'Debug E-Mail Address',
470
                                                                            'desc' => 'All parameters of an invalid transaction will be sent to this email address.'),
471
                      'MODULE_PAYMENT_SAGE_PAY_SERVER_SORT_ORDER' => array('title' => 'Sort order of display.',
472
                                                                           'desc' => 'Sort order of display. Lowest is displayed first.',
473
                                                                           'value' => '0'));
474
475
      return $params;
476
    }
477
478 View Code Duplication
    function sendTransactionToGateway($url, $parameters) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
479
      $server = parse_url($url);
480
481
      if (isset($server['port']) === false) {
482
        $server['port'] = ($server['scheme'] == 'https') ? 443 : 80;
483
      }
484
485
      if (isset($server['path']) === false) {
486
        $server['path'] = '/';
487
      }
488
489
      $curl = curl_init($server['scheme'] . '://' . $server['host'] . $server['path'] . (isset($server['query']) ? '?' . $server['query'] : ''));
490
      curl_setopt($curl, CURLOPT_PORT, $server['port']);
491
      curl_setopt($curl, CURLOPT_HEADER, false);
492
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
493
      curl_setopt($curl, CURLOPT_FORBID_REUSE, true);
494
      curl_setopt($curl, CURLOPT_FRESH_CONNECT, true);
495
      curl_setopt($curl, CURLOPT_POST, true);
496
      curl_setopt($curl, CURLOPT_POSTFIELDS, $parameters);
497
498
      if ( MODULE_PAYMENT_SAGE_PAY_SERVER_VERIFY_SSL == 'True' ) {
499
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
500
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
501
502
        if ( is_file(OSCOM::getConfig('dir_root', 'Shop') . 'ext/modules/payment/sage_pay/sagepay.com.crt') ) {
503
          curl_setopt($curl, CURLOPT_CAINFO, OSCOM::getConfig('dir_root', 'Shop') . 'ext/modules/payment/sage_pay/sagepay.com.crt');
504
        } elseif ( is_file(OSCOM::getConfig('dir_root', 'Shop') . 'includes/cacert.pem') ) {
505
          curl_setopt($curl, CURLOPT_CAINFO, OSCOM::getConfig('dir_root', 'Shop') . 'includes/cacert.pem');
506
        }
507
      } else {
508
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
509
      }
510
511
      if ( tep_not_null(MODULE_PAYMENT_SAGE_PAY_SERVER_PROXY) ) {
512
        curl_setopt($curl, CURLOPT_HTTPPROXYTUNNEL, true);
513
        curl_setopt($curl, CURLOPT_PROXY, MODULE_PAYMENT_SAGE_PAY_SERVER_PROXY);
514
      }
515
516
      $result = curl_exec($curl);
517
518
      curl_close($curl);
519
520
      return $result;
521
    }
522
523
// format prices without currency formatting
524 View Code Duplication
    function format_raw($number, $currency_code = '', $currency_value = '') {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
525
      global $currencies;
526
527
      if (empty($currency_code) || !$currencies->is_set($currency_code)) {
528
        $currency_code = $_SESSION['currency'];
529
      }
530
531
      if (empty($currency_value) || !is_numeric($currency_value)) {
532
        $currency_value = $currencies->currencies[$currency_code]['value'];
533
      }
534
535
      return number_format(tep_round($number * $currency_value, $currencies->currencies[$currency_code]['decimal_places']), $currencies->currencies[$currency_code]['decimal_places'], '.', '');
536
    }
537
538 View Code Duplication
    function loadErrorMessages() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
539
      $errors = array();
540
541
      if (is_file(dirname(__FILE__) . '/../../../ext/modules/payment/sage_pay/errors.php')) {
542
        include(dirname(__FILE__) . '/../../../ext/modules/payment/sage_pay/errors.php');
543
      }
544
545
      $this->_error_messages = $errors;
0 ignored issues
show
Bug introduced by
The property _error_messages does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
546
    }
547
548 View Code Duplication
    function getErrorMessageNumber($string) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
549
      if (!isset($this->_error_messages)) {
550
        $this->loadErrorMessages();
551
      }
552
553
      $error = explode(' ', $string, 2);
554
555
      if (is_numeric($error[0]) && $this->errorMessageNumberExists($error[0])) {
556
        return $error[0];
557
      }
558
559
      return false;
560
    }
561
562 View Code Duplication
    function getErrorMessage($number) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
563
      if (!isset($this->_error_messages)) {
564
        $this->loadErrorMessages();
565
      }
566
567
      if (is_numeric($number) && $this->errorMessageNumberExists($number)) {
568
        return $this->_error_messages[$number];
569
      }
570
571
      return false;
572
    }
573
574 View Code Duplication
    function errorMessageNumberExists($number) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
575
      if (!isset($this->_error_messages)) {
576
        $this->loadErrorMessages();
577
      }
578
579
      return (is_numeric($number) && isset($this->_error_messages[$number]));
580
    }
581
582
    function formatURL($url) {
583
      return str_replace('&amp;', '&', $url);
584
    }
585
586
    function getTestLinkInfo() {
587
      $dialog_title = OSCOM::getDef('module_payment_sage_pay_server_dialog_connection_title');
588
      $dialog_button_close = OSCOM::getDef('module_payment_sage_pay_server_dialog_connection_button_close');
589
      $dialog_success = OSCOM::getDef('module_payment_sage_pay_server_dialog_connection_success');
590
      $dialog_failed = OSCOM::getDef('module_payment_sage_pay_server_dialog_connection_failed');
591
      $dialog_error = OSCOM::getDef('module_payment_sage_pay_server_dialog_connection_error');
592
      $dialog_connection_time = OSCOM::getDef('module_payment_sage_pay_server_dialog_connection_time');
593
594
      $test_url = OSCOM::link('modules.php', 'set=payment&module=' . $this->code . '&action=install&subaction=conntest');
595
596
      $js = <<<EOD
597
<script>
598
if ( typeof jQuery == 'undefined' ) {
599
  document.write('<scr' + 'ipt src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></scr' + 'ipt>');
600
  document.write('<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/redmond/jquery-ui.css" />');
601
  document.write('<scr' + 'ipt src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></scr' + 'ipt>');
602
}
603
</script>
604
605
<script>
606
$(function() {
607
  $('#tcdprogressbar').progressbar({
608
    value: false
609
  });
610
});
611
612
function openTestConnectionDialog() {
613
  var d = $('<div>').html($('#testConnectionDialog').html()).dialog({
614
    modal: true,
615
    title: '{$dialog_title}',
616
    buttons: {
617
      '{$dialog_button_close}': function () {
618
        $(this).dialog('destroy');
619
      }
620
    }
621
  });
622
623
  var timeStart = new Date().getTime();
624
625
  $.ajax({
626
    url: '{$test_url}'
627
  }).done(function(data) {
628
    if ( data == '1' ) {
629
      d.find('#testConnectionDialogProgress').html('<p style="font-weight: bold; color: green;">{$dialog_success}</p>');
630
    } else {
631
      d.find('#testConnectionDialogProgress').html('<p style="font-weight: bold; color: red;">{$dialog_failed}</p>');
632
    }
633
  }).fail(function() {
634
    d.find('#testConnectionDialogProgress').html('<p style="font-weight: bold; color: red;">{$dialog_error}</p>');
635
  }).always(function() {
636
    var timeEnd = new Date().getTime();
637
    var timeTook = new Date(0, 0, 0, 0, 0, 0, timeEnd-timeStart);
638
639
    d.find('#testConnectionDialogProgress').append('<p>{$dialog_connection_time} ' + timeTook.getSeconds() + '.' + timeTook.getMilliseconds() + 's</p>');
640
  });
641
}
642
</script>
643
EOD;
644
645
      $info = '<p><img src="images/icons/locked.gif" border="0">&nbsp;<a href="javascript:openTestConnectionDialog();" style="text-decoration: underline; font-weight: bold;">' . OSCOM::getDef('module_payment_sage_pay_server_dialog_connection_link_title') . '</a></p>' .
646
              '<div id="testConnectionDialog" style="display: none;"><p>';
647
648
      if ( MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_SERVER == 'Live' ) {
649
        $info .= 'Live Server:<br />https://live.sagepay.com/gateway/service/vspserver-register.vsp';
650
      } else {
651
        $info .= 'Test Server:<br />https://test.sagepay.com/gateway/service/vspserver-register.vsp';
652
      }
653
654
      $info .= '</p><div id="testConnectionDialogProgress"><p>' . OSCOM::getDef('module_payment_sage_pay_server_dialog_connection_general_text') . '</p><div id="tcdprogressbar"></div></div></div>' .
655
               $js;
656
657
      return $info;
658
    }
659
660 View Code Duplication
    function getTestConnectionResult() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
661
      if ( MODULE_PAYMENT_SAGE_PAY_SERVER_TRANSACTION_SERVER == 'Live' ) {
662
        $gateway_url = 'https://live.sagepay.com/gateway/service/vspserver-register.vsp';
663
      } else {
664
        $gateway_url = 'https://test.sagepay.com/gateway/service/vspserver-register.vsp';
665
      }
666
667
      $params = array('VPSProtocol' => $this->api_version,
668
                      'ReferrerID' => 'C74D7B82-E9EB-4FBD-93DB-76F0F551C802',
669
                      'Vendor' => substr(MODULE_PAYMENT_SAGE_PAY_DIRECT_VENDOR_LOGIN_NAME, 0, 15),
670
                      'Amount' => 0,
671
                      'Currency' => DEFAULT_CURRENCY);
672
673
      $ip_address = HTTP::getIpAddress();
674
675
      if ( !empty($ip_address) && (ip2long($ip_address) != -1) && (ip2long($ip_address) != false) ) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing ip2long($ip_address) of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
676
        $params['ClientIPAddress']= $ip_address;
677
      }
678
679
      $post_string = '';
680
681
      foreach ($params as $key => $value) {
682
        $post_string .= $key . '=' . urlencode(trim($value)) . '&';
683
      }
684
685
      $response = $this->sendTransactionToGateway($gateway_url, $post_string);
686
687
      if ( $response != false ) {
688
        return 1;
689
      }
690
691
      return -1;
692
    }
693
694 View Code Duplication
    function sendDebugEmail($response = array()) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
695
      if (tep_not_null(MODULE_PAYMENT_SAGE_PAY_SERVER_DEBUG_EMAIL)) {
696
        $email_body = '';
697
698
        if (!empty($response)) {
699
          $email_body .= 'RESPONSE:' . "\n\n" . print_r($response, true) . "\n\n";
700
        }
701
702
        if (!empty($_POST)) {
703
          $email_body .= '$_POST:' . "\n\n" . print_r($_POST, true) . "\n\n";
704
        }
705
706
        if (!empty($_GET)) {
707
          $email_body .= '$_GET:' . "\n\n" . print_r($_GET, true) . "\n\n";
708
        }
709
710
        if (!empty($email_body)) {
711
          $debugEmail = new Mail(MODULE_PAYMENT_SAGE_PAY_SERVER_DEBUG_EMAIL, null, STORE_OWNER_EMAIL_ADDRESS, STORE_OWNER, 'Sage Pay Server Debug E-Mail');
712
          $debugEmail->setBody($email_body);
713
          $debugEmail->send();
714
        }
715
      }
716
    }
717
  }
718
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
719