Completed
Push — trunk ( 34029c...0f5c9b )
by SuperNova.WS
03:54
created

sn_sys_load_php_files()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 6
eloc 9
nc 5
nop 2
dl 0
loc 12
rs 8.8571
c 3
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 29 and the first side effect is on line 4.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
4
require_once('general/math.php');
5
require_once('general/compatibility.php');
6
require_once('general/params.php');
7
require_once('general/nickRender.php');
8
require_once('general/formatters.php');
9
require_once('general/validators.php');
10
require_once('general/unitFunctions.php');
11
require_once('general/playerFunctions.php');
12
require_once('general/planetFunctions.php');
13
require_once('general/urlAndHttp.php');
14
require_once('general_pname.php');
15
16
17
// HOOKS AND HANDLERS ----------------------------------------------------------------------------------------------------------------
18
/**
19
 * Function wrapping
20
 *
21
 * Due glitch in PHP 5.3.1 SuperNova is incompatible with this version
22
 * Reference: https://bugs.php.net/bug.php?id=50394
23
 *
24
 * @param string $func_name
25
 * @param array  $func_arg
26
 *
27
 * @return mixed
28
 */
29
function sn_function_call($func_name, $func_arg = array()) {
30
  global $functions; // All data in $functions should be normalized to valid 'callable' state: '<function_name>'|array('<object_name>', '<method_name>')
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
31
32
  if (is_array($functions[$func_name]) && !is_callable($functions[$func_name])) {
33
    // Chain-callable functions should be made as following:
34
    // 1. Never use incomplete calls with parameters "by default"
35
    // 2. Reserve last parameter for cumulative result
36
    // 3. Use same format for original value and cumulative result (if there is original value)
37
    // 4. Honor cumulative result
38
    // 5. Return cumulative result
39
    foreach ($functions[$func_name] as $func_chain_name) {
40
      // По идее - это уже тут не нужно, потому что оно все должно быть callable к этому моменту
41
      // Но для старых модулей...
42
      if (is_callable($func_chain_name)) {
43
        $result = call_user_func_array($func_chain_name, $func_arg);
44
      }
45
    }
46
  } else {
47
    // TODO: This is left for backward compatibility. Appropriate code should be rewrote!
48
    $func_name = isset($functions[$func_name]) && is_callable($functions[$func_name]) ? $functions[$func_name] : ('sn_' . $func_name);
49
    if (is_callable($func_name)) {
50
      $result = call_user_func_array($func_name, $func_arg);
51
    }
52
  }
53
54
  return $result;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
55
}
56
57
/**
58
 * @param        $hook_list
59
 * @param        $template
60
 * @param string $hook_type - тип хука 'model' или 'view'
61
 * @param string $page_name - имя страницы, для которого должен был быть выполнен хук
62
 */
63
function execute_hooks(&$hook_list, &$template, $hook_type = null, $page_name = null) {
64
  if (!empty($hook_list)) {
65
    foreach ($hook_list as $hook) {
66
      if (is_callable($hook_call = (is_string($hook) ? $hook : (is_array($hook) ? $hook['callable'] : $hook->callable)))) {
67
        $template = call_user_func($hook_call, $template, $hook_type, $page_name);
68
      }
69
    }
70
  }
71
}
72
73
function sn_sys_handler_add(&$functions, $handler_list, $class_module_name = '', $sub_type = '') {
74
  if (isset($handler_list) && is_array($handler_list) && !empty($handler_list)) {
75
    foreach ($handler_list as $function_name => $function_data) {
76
      sys_handler_add_one($functions, $function_name, $function_data, $class_module_name, $sub_type);
77
    }
78
  }
79
}
80
81
/**
82
 * Adding one handler for specific function name
83
 *
84
 * @param callable[]   $functions
85
 * @param string       $function_name
86
 * @param string|array $function_data
87
 * @param string       $class_module_name
88
 * @param string       $sub_type
89
 */
90
function sys_handler_add_one(&$functions, $function_name, $function_data, $class_module_name, $sub_type) {
91
  if (is_string($function_data)) {
92
    $override_with = &$function_data;
93
  } elseif (isset($function_data['callable'])) {
94
    $override_with = &$function_data['callable'];
95
  }
96
97
  $overwrite = $override_with[0] == '*';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $override_with does not seem to be defined for all execution paths leading up to this point.
Loading history...
98
  if ($overwrite) {
99
    $override_with = substr($override_with, 1);
100
  }
101
102
  if (($point_position = strpos($override_with, '.')) === false && $class_module_name) {
103
    $override_with = array($class_module_name, $override_with);
104
  } elseif ($point_position == 0) {
105
    $override_with = substr($override_with, 1);
106
  } elseif ($point_position > 0) {
107
    $override_with = array(substr($override_with, 0, $point_position), substr($override_with, $point_position + 1));
108
  }
109
110
  if ($overwrite) {
111
    $functions[$function_name] = array();
112
  } elseif (!isset($functions[$function_name])) {
113
    $functions[$function_name] = array();
114
    $sn_function_name = 'sn_' . $function_name . ($sub_type ? '_' . $sub_type : '');
115
    //if(is_callable($sn_function_name))
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
116
    {
117
      $functions[$function_name][] = $sn_function_name;
118
    }
119
  }
120
121
  $functions[$function_name][] = $function_data;
122
}
123
124
125
// FLEET FUNCTIONS -----------------------------------------------------------------------------------------------------
126
/**
127
 * @param \Fleet\MissionExplore $result
128
 *
129
 * @return \Fleet\MissionExplore
130
 */
131
function flt_mission_explore_addon_object($result) { return sn_function_call('flt_mission_explore_addon_object', [$result]); }
132
133
/**
134
 * @param \Fleet\MissionExplore $result
135
 *
136
 * @return \Fleet\MissionExplore
137
 */
138
function sn_flt_mission_explore_addon_object($result) {
139
  return $result;
140
}
141
142
// FILE FUNCTIONS ----------------------------------------------------------------------------------------------------------------
143
function sys_file_read($filename) {
144
  return @file_get_contents($filename);
145
}
146
147
function sys_file_write($filename, $content) {
148
  return @file_put_contents($filename, $content, FILE_APPEND);
149
}
150
151
function sn_sys_load_php_files($dir_name, $load_extension = 'php') {
152
  if (file_exists($dir_name)) {
153
    $dir = opendir($dir_name);
154
    while (($file = readdir($dir)) !== false) {
0 ignored issues
show
Bug introduced by
It seems like $dir can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

154
    while (($file = readdir(/** @scrutinizer ignore-type */ $dir)) !== false) {
Loading history...
155
      if ($file == '..' || $file == '.') {
156
        continue;
157
      }
158
159
      $full_filename = $dir_name . $file;
160
      $extension = substr($full_filename, -strlen($load_extension));
161
      if ($extension == $load_extension) {
162
        require_once($full_filename);
163
      }
164
    }
165
  }
166
}
167
168
169
// GLOBAL DATA FUNCTIONS -----------------------------------------------------------------------------------------------
170
/**
171
 * Simple wrapper to get base or calculated value for supplied unitSnId
172
 *
173
 * @param int  $unitSnId
174
 * @param bool $plain
175
 *
176
 * @return float|int
177
 */
178
function getValueFromStorage($unitSnId, $plain = false) {
179
  $valueObject = SN::$gc->valueStorage->getValueObject($unitSnId);
180
181
  return $plain ? $valueObject->base : $valueObject->getValue();
182
}
183
184
/**
185
 * Get game resource multiplier aka mining speed
186
 *
187
 * @param bool $plain
188
 *
189
 * @return float|int
190
 */
191
function game_resource_multiplier($plain = false) {
192
  return getValueFromStorage(UNIT_SERVER_SPEED_MINING, $plain);
0 ignored issues
show
Bug introduced by
UNIT_SERVER_SPEED_MINING of type string is incompatible with the type integer expected by parameter $unitSnId of getValueFromStorage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

192
  return getValueFromStorage(/** @scrutinizer ignore-type */ UNIT_SERVER_SPEED_MINING, $plain);
Loading history...
193
}
194
195
/**
196
 * Get game speed aka manufacturing speed
197
 *
198
 * @param bool $plain
199
 *
200
 * @return float|int
201
 */
202
function get_game_speed($plain = false) {
203
  return getValueFromStorage(UNIT_SERVER_SPEED_BUILDING, $plain);
0 ignored issues
show
Bug introduced by
UNIT_SERVER_SPEED_BUILDING of type string is incompatible with the type integer expected by parameter $unitSnId of getValueFromStorage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

203
  return getValueFromStorage(/** @scrutinizer ignore-type */ UNIT_SERVER_SPEED_BUILDING, $plain);
Loading history...
204
}
205
206
/**
207
 * Get fleet flying speed aka... hmph... fleet flying speed
208
 *
209
 * @param bool $plain
210
 *
211
 * @return float|int
212
 */
213
function flt_server_flight_speed_multiplier($plain = false) {
214
  return getValueFromStorage(UNIT_SERVER_SPEED_FLEET, $plain);
0 ignored issues
show
Bug introduced by
UNIT_SERVER_SPEED_FLEET of type string is incompatible with the type integer expected by parameter $unitSnId of getValueFromStorage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

214
  return getValueFromStorage(/** @scrutinizer ignore-type */ UNIT_SERVER_SPEED_FLEET, $plain);
Loading history...
215
}
216
217
218
/**
219
 * Получение стоимости ММ в валюте сервера
220
 *
221
 * @param bool|false $plain
222
 *
223
 * @return mixed
224
 */
225
function get_mm_cost($plain = false) {
226
  $result = null;
227
228
  return sn_function_call('get_mm_cost', array($plain, &$result));
229
}
230
231
function sn_get_mm_cost($plain = false, &$result) {
232
  return $result = SN::$config->payment_currency_exchange_mm_ ? SN::$config->payment_currency_exchange_mm_ : 20000;
233
}
234
235
/**
236
 * Получение курса обмены валюты в серверную валюту
237
 *
238
 * @param $currency_symbol
239
 *
240
 * @return float
241
 */
242
function get_exchange_rate($currency_symbol) {
243
  $currency_symbol = strtolower($currency_symbol);
244
  $config_field = 'payment_currency_exchange_' . $currency_symbol;
245
246
  // Заворачиваем получение стоимости ММ через перекрываемую процедуру
247
  $exchange_rate = floatval($currency_symbol == 'mm_' ? get_mm_cost() : SN::$config->$config_field);
248
249
  return $exchange_rate;
250
}
251
252
function sys_stat_get_user_skip_list() {
253
  $result = array();
254
255
  $user_skip_list = array();
256
257
  if (SN::$config->stats_hide_admins) {
258
    $user_skip_list[] = '`authlevel` > 0';
259
  }
260
261
  if (SN::$config->stats_hide_player_list) {
262
    $temp = explode(',', SN::$config->stats_hide_player_list);
263
    foreach ($temp as $user_id) {
264
      $user_id = floatval($user_id);
265
      if ($user_id) {
266
        $user_skip_list[] = '`id` = ' . $user_id;
267
      }
268
    }
269
  }
270
271
  if (!empty($user_skip_list)) {
272
    $user_skip_list = implode(' OR ', $user_skip_list);
273
    $user_skip_query = db_user_list($user_skip_list);
0 ignored issues
show
Deprecated Code introduced by
The function db_user_list() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

273
    $user_skip_query = /** @scrutinizer ignore-deprecated */ db_user_list($user_skip_list);
Loading history...
274
    if (!empty($user_skip_query)) {
275
      foreach ($user_skip_query as $user_skip_row) {
276
        $result[$user_skip_row['id']] = $user_skip_row['id'];
277
      }
278
    }
279
  }
280
281
  return $result;
282
}
283
284
function market_get_autoconvert_cost() {
285
  return SN::$config->rpg_cost_exchange ? SN::$config->rpg_cost_exchange * 3 : 3000;
0 ignored issues
show
Bug Best Practice introduced by
The property rpg_cost_exchange does not exist on classConfig. Since you implemented __get, consider adding a @property annotation.
Loading history...
286
}
287
288
function sn_powerup_get_price_matrix($powerup_id, $powerup_unit = false, $level_max = null, $plain = false) {
289
  $result = null;
290
291
  return sn_function_call('sn_powerup_get_price_matrix', array($powerup_id, $powerup_unit, $level_max, $plain, &$result));
292
}
293
294
function sn_sn_powerup_get_price_matrix($powerup_id, $powerup_unit = false, $level_max = null, $plain = false, &$result) {
295
  global $sn_powerup_buy_discounts;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
296
297
  $result = array();
298
299
  $powerup_data = get_unit_param($powerup_id);
300
  $is_upgrade = !empty($powerup_unit) && $powerup_unit;
301
302
  $level_current = $term_original = $time_left = 0;
303
  if ($is_upgrade) {
304
    $time_finish = strtotime($powerup_unit['unit_time_finish']);
305
    $time_left = max(0, $time_finish - SN_TIME_NOW);
306
    if ($time_left > 0) {
307
      $term_original = $time_finish - strtotime($powerup_unit['unit_time_start']);
308
      $level_current = $powerup_unit['unit_level'];
309
    }
310
  }
311
312
  $level_max = $level_max > $powerup_data[P_MAX_STACK] ? $level_max : $powerup_data[P_MAX_STACK];
313
  $original_cost = 0;
314
  for ($i = 1; $i <= $level_max; $i++) {
315
    $base_cost = eco_get_total_cost($powerup_id, $i);
316
    $base_cost = $base_cost[BUILD_CREATE][RES_DARK_MATTER];
317
    foreach ($sn_powerup_buy_discounts as $period => $discount) {
318
      $upgrade_price = floor($base_cost * $discount * $period / PERIOD_MONTH);
319
      $result[$i][$period] = $upgrade_price;
320
      $original_cost = $is_upgrade && $i == $level_current && $period <= $term_original ? $upgrade_price : $original_cost;
321
    }
322
  }
323
324
  if ($is_upgrade && $time_left) {
325
    $term_original = round($term_original / PERIOD_DAY);
326
    $time_left = min(floor($time_left / PERIOD_DAY), $term_original);
327
    $cost_left = $term_original > 0 ? ceil($time_left / $term_original * $original_cost) : 0;
328
329
    array_walk_recursive($result, function (&$value) use ($cost_left) {
330
      $value -= $cost_left;
331
    });
332
  }
333
334
  return $result;
335
}
336
337
/**
338
 * @param $price_matrix_plain
339
 * @param $price_matrix_original
340
 * @param $price_matrix_upgrade
341
 * @param $user_dark_matter
342
 *
343
 * @return array
344
 *
345
 * Used in player_premium and interface_batch_operation modules
346
 */
347
function price_matrix_templatize(&$price_matrix_plain, &$price_matrix_original, &$price_matrix_upgrade, $user_dark_matter) {
348
  $prices = array();
349
  foreach ($price_matrix_original as $level_num => $level_data) {
350
    $price_per_period = array();
351
    foreach ($level_data as $period => $price) {
352
      $price_per_period[$period] = array(
353
        'PERIOD'             => $period,
354
        'PRICE_ORIGIN'       => $price,
355
        'PRICE_ORIGIN_TEXT'  => HelperString::numberFloorAndFormat($price),
356
        'PRICE_ORIGIN_CLASS' => prettyNumberGetClass($price, $user_dark_matter),
357
        'PRICE_UPGRADE'      => $price_matrix_upgrade[$level_num][$period],
358
        'PRICE_UPGRADE_TEXT' => HelperString::numberFloorAndFormat($price_matrix_upgrade[$level_num][$period]),
359
      );
360
      if (isset($price_matrix_plain[$level_num][$period])) {
361
        $price_per_period[$period] += array(
362
          'PRICE_PLAIN_PERCENT' => ceil(100 - ($price / $price_matrix_plain[$level_num][$period]) * 100),
363
          'PRICE_PLAIN'         => $price_matrix_plain[$level_num][$period],
364
          'PRICE_PLAIN_TEXT'    => HelperString::numberFloorAndFormat($price_matrix_plain[$level_num][$period]),
365
        );
366
      }
367
    }
368
369
    $prices[$level_num] = array(
370
      '.'     => array('period' => $price_per_period),
371
      'LEVEL' => $level_num,
372
    );
373
  }
374
375
  return $prices;
376
}
377
378
379
// TOOLS & UTILITIES ----------------------------------------------------------------------------------------------------------------
380
/**
381
 * Generates random string of $length symbols from $allowed_chars charset
382
 *
383
 * @param int    $length
384
 * @param string $allowed_chars
385
 *
386
 * @return string
387
 */
388
function sys_random_string($length = 16, $allowed_chars = SN_SYS_SEC_CHARS_ALLOWED) {
389
  $allowed_length = strlen($allowed_chars);
390
391
  $random_string = '';
392
  for ($i = 0; $i < $length; $i++) {
393
    $random_string .= $allowed_chars[mt_rand(0, $allowed_length - 1)];
394
  }
395
396
  return $random_string;
397
}
398
399
function array_merge_recursive_numeric($array1, $array2) {
400
  if (!empty($array2) && is_array($array2)) {
401
    foreach ($array2 as $key => $value) {
402
      $array1[$key] = !isset($array1[$key]) || !is_array($array1[$key]) ? $value : array_merge_recursive_numeric($array1[$key], $value);
403
    }
404
  }
405
406
  return $array1;
407
}
408
409
function sn_sys_array_cumulative_sum(&$array) {
410
  $accum = 0;
411
  foreach ($array as &$value) {
412
    $accum += $value;
413
    $value = $accum;
414
  }
415
}
416
417
function print_rr($var, $capture = false) {
418
  $print = '<pre>' . htmlspecialchars(print_r($var, true)) . '</pre>';
419
  if ($capture) {
420
    return $print;
421
  } else {
422
    print($print);
423
  }
424
}
425
426
/**
427
 * Returns unique string ID for total fleets on planet
428
 *
429
 * @param array $planetTemplatized
430
 *
431
 * @return int|string
432
 */
433
function getUniqueFleetId($planetTemplatized) {
434
  return empty($planetTemplatized['id']) ? 0 : sprintf(FLEET_ID_TEMPLATE, $planetTemplatized['id']);
435
}
436
437
/**
438
 * @param array $context
439
 *
440
 * @return array
441
 */
442
function getLocationFromContext($context = []) {
443
  if (!empty($context[LOC_FLEET])) {
444
    return [LOC_FLEET, $context[LOC_FLEET]['fleet_id']];
445
  } elseif (!empty($context[LOC_PLANET])) {
446
    return [LOC_PLANET, $context[LOC_PLANET]['id']];
447
  } elseif (!empty($context[LOC_USER])) {
448
    return [LOC_USER, $context[LOC_USER]['id']];
449
  } else {
450
    return [LOC_SERVER, 0];
451
  }
452
453
}
454
455
456
//
457
458
459
// MAIL ----------------------------------------------------------------------------------------------------------------
460
function mymail($email_unsafe, $title, $body, $from = '', $html = false) {
461
  $from = trim($from ? $from : SN::$config->game_adminEmail);
462
463
  $head = '';
464
  $head .= "Content-Type: text/" . ($html ? 'html' : 'plain') . "; charset=utf-8 \r\n";
465
  $head .= "Date: " . date('r') . " \r\n";
466
  $head .= "Return-Path: " . SN::$config->game_adminEmail . " \r\n";
467
  $head .= "From: {$from} \r\n";
468
  $head .= "Sender: {$from} \r\n";
469
  $head .= "Reply-To: {$from} \r\n";
470
//  $head .= "Organization: {$org} \r\n";
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
471
  $head .= "X-Sender: {$from} \r\n";
472
  $head .= "X-Priority: 3 \r\n";
473
474
  $body = str_replace("\r\n", "\n", $body);
475
  $body = str_replace("\n", "\r\n", $body);
476
477
  if ($html) {
478
    $body = '<html><head><base href="' . SN_ROOT_VIRTUAL . '"></head><body>' . nl2br($body) . '</body></html>';
479
  }
480
481
  $title = '=?UTF-8?B?' . base64_encode($title) . '?=';
482
483
  return @mail($email_unsafe, $title, $body, $head);
484
}
485
486
487
//
488
489
490
// VERSION FUNCTIONS ----------------------------------------------------------------------------------------------------------------
491
function sn_version_compare_extra($version) {
492
  static $version_regexp = '#(\d+)([a-f])(\d+)(?:\.(\d+))*#';
493
  preg_match($version_regexp, $version, $version);
494
  unset($version[0]);
495
  $version[2] = ord($version[2]) - ord('a');
496
497
  return implode('.', $version);
498
}
499
500
function sn_version_compare($ver1, $ver2) {
501
  return version_compare(sn_version_compare_extra($ver1), sn_version_compare_extra($ver2));
502
}
503