Issues (1369)

includes/general/general.php (7 issues)

1
<?php /** @noinspection PhpDeprecationInspection */
2
/** @noinspection PhpOptionalBeforeRequiredParametersInspection */
3
/** @noinspection PhpUnusedParameterInspection */
4
5
6
require_once('general_math.php');
7
require_once('general_compatibility.php');
8
require_once('general_params.php');
9
require_once('general_nickRender.php');
10
require_once('general_formatters.php');
11
require_once('general_validators.php');
12
require_once('general_unitFunctions.php');
13
require_once('general_playerFunctions.php');
14
require_once('general_planetFunctions.php');
15
require_once('general_urlAndHttp.php');
16
17
require_once('general_pname.php');
18
19
// HOOKS AND HANDLERS ----------------------------------------------------------------------------------------------------------------
20
/**
21
 * Function wrapping
22
 *
23
 * Due glitch in PHP 5.3.1 SuperNova is incompatible with this version
24
 * Reference: https://bugs.php.net/bug.php?id=50394
25
 *
26
 * @param string $func_name
27
 * @param array  $func_arg
28
 *
29
 * @return mixed
30
 */
31
function sn_function_call($func_name, $func_arg = array()) {
32
  global $functions; // All data in $functions should be normalized to valid 'callable' state: '<function_name>'|array('<object_name>', '<method_name>')
33
34
  $result = null;
35
  if (is_array($functions[$func_name]) && !is_callable($functions[$func_name])) {
36
    // Chain-callable functions should be made as following:
37
    // 1. Never use incomplete calls with parameters "by default"
38
    // 2. Reserve last parameter for cumulative result
39
    // 3. Use same format for original value and cumulative result (if there is original value)
40
    // 4. Honor cumulative result
41
    // 5. Return cumulative result
42
    foreach ($functions[$func_name] as $func_chain_name) {
43
      // По идее - это уже тут не нужно, потому что оно все должно быть callable к этому моменту
44
      // Но для старых модулей...
45
      if (is_callable($func_chain_name)) {
46
        $result = call_user_func_array($func_chain_name, $func_arg);
47
      }
48
    }
49
  } else {
50
    // TODO: This is left for backward compatibility. Appropriate code should be rewrote!
51
    $func_name = isset($functions[$func_name]) && is_callable($functions[$func_name]) ? $functions[$func_name] : ('sn_' . $func_name);
52
    if (is_callable($func_name)) {
53
      $result = call_user_func_array($func_name, $func_arg);
54
    }
55
  }
56
57
  return $result;
58
}
59
60
/**
61
 * @param        $hook_list
62
 * @param        $template
63
 * @param string $hook_type - тип хука 'model' или 'view'
64
 * @param string $page_name - имя страницы, для которого должен был быть выполнен хук
65
 *
66
 * @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection
67
 */
68
function execute_hooks(&$hook_list, &$template, $hook_type = null, $page_name = null) {
69
  if (!empty($hook_list)) {
70
    foreach ($hook_list as $hook) {
71
      if (is_callable($hook_call = (is_string($hook) ? $hook : (is_array($hook) ? $hook['callable'] : $hook->callable)))) {
72
        $template = call_user_func($hook_call, $template, $hook_type, $page_name);
73
      }
74
    }
75
  }
76
}
77
78
function sn_sys_handler_add(&$functions, $handler_list, $class_module_name = '', $sub_type = '') {
79
  if (isset($handler_list) && is_array($handler_list) && !empty($handler_list)) {
80
    foreach ($handler_list as $function_name => $function_data) {
81
      sys_handler_add_one($functions, $function_name, $function_data, $class_module_name, $sub_type);
82
    }
83
  }
84
}
85
86
/**
87
 * Adding one handler for specific function name
88
 *
89
 * @param callable[][] $functions
90
 * @param string       $function_name
91
 * @param string|array $function_data
92
 * @param string       $class_module_name
93
 * @param string       $sub_type
94
 */
95
function sys_handler_add_one(&$functions, $function_name, $function_data, $class_module_name, $sub_type) {
96
  if (is_string($function_data)) {
97
    $override_with = &$function_data;
98
  } elseif (isset($function_data['callable'])) {
99
    $override_with = &$function_data['callable'];
100
  }
101
102
  /** @noinspection PhpUndefinedVariableInspection */
103
  $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...
104
  $prepend   = $override_with[0] == '+';
105
  if ($overwrite || $prepend) {
106
    $override_with = substr($override_with, 1);
107
  }
108
109
  if (($point_position = strpos($override_with, '.')) === false && $class_module_name) {
110
    $override_with = array($class_module_name, $override_with);
111
  } elseif ($point_position == 0) {
112
    $override_with = substr($override_with, 1);
113
  } elseif ($point_position > 0) {
114
    $override_with = array(substr($override_with, 0, $point_position), substr($override_with, $point_position + 1));
115
  }
116
117
  if ($overwrite) {
118
    $functions[$function_name] = array();
119
  } elseif (!isset($functions[$function_name])) {
120
    $functions[$function_name] = array();
121
    $sn_function_name          = 'sn_' . $function_name . ($sub_type ? '_' . $sub_type : '');
122
    //if(is_callable($sn_function_name))
123
    {
124
      $functions[$function_name][] = $sn_function_name;
125
    }
126
  }
127
128
  if ($prepend) {
129
    array_unshift($functions[$function_name], $function_data);
130
  } else {
131
    $functions[$function_name][] = $function_data;
132
  }
133
}
134
135
136
// FLEET FUNCTIONS -----------------------------------------------------------------------------------------------------
137
///**
138
// * @param MissionExplore $result
139
// *
140
// * @return MissionExplore
141
// */
142
//function flt_mission_explore_addon_object($result) { return sn_function_call('flt_mission_explore_addon_object', [$result]); }
143
//
144
///**
145
// * @param MissionExplore $result
146
// *
147
// * @return MissionExplore
148
// */
149
//function sn_flt_mission_explore_addon_object($result) {
150
//  return $result;
151
//}
152
153
// FILE FUNCTIONS ----------------------------------------------------------------------------------------------------------------
154
/** @noinspection PhpUnused */
155
function sys_file_read($filename) {
156
  return @file_get_contents($filename);
157
}
158
159
/** @noinspection PhpUnused */
160
function sys_file_write($filename, $content) {
161
  return @file_put_contents($filename, $content, FILE_APPEND);
162
}
163
164
function sn_sys_load_php_files($dir_name, $load_extension = 'php') {
165
  if (file_exists($dir_name)) {
166
    $dir = opendir($dir_name);
167
    while (($file = readdir($dir)) !== false) {
168
      if ($file == '..' || $file == '.') {
169
        continue;
170
      }
171
172
      $full_filename = $dir_name . $file;
173
      $extension     = substr($full_filename, -strlen($load_extension));
174
      if ($extension == $load_extension) {
175
        require_once($full_filename);
176
      }
177
    }
178
  }
179
}
180
181
182
// GLOBAL DATA FUNCTIONS -----------------------------------------------------------------------------------------------
183
/**
184
 * Simple wrapper to get base or calculated value for supplied unitSnId
185
 *
186
 * @param int  $unitSnId
187
 * @param bool $plain
188
 *
189
 * @return float|int
190
 */
191
function getValueFromStorage($unitSnId, $plain = false) {
192
  $valueObject = SN::$gc->valueStorage->getValueObject($unitSnId);
193
194
  return $plain ? $valueObject->base : $valueObject->getValue();
195
}
196
197
/**
198
 * Get game resource multiplier aka mining speed
199
 *
200
 * @param bool $plain
201
 *
202
 * @return float|int
203
 */
204
function game_resource_multiplier($plain = false) {
205
  return getValueFromStorage(UNIT_SERVER_SPEED_MINING, $plain);
0 ignored issues
show
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

205
  return getValueFromStorage(/** @scrutinizer ignore-type */ UNIT_SERVER_SPEED_MINING, $plain);
Loading history...
206
}
207
208
/**
209
 * Get game speed aka manufacturing speed
210
 *
211
 * @param bool $plain
212
 *
213
 * @return float|int
214
 */
215
function get_game_speed($plain = false) {
216
  return getValueFromStorage(UNIT_SERVER_SPEED_BUILDING, $plain);
0 ignored issues
show
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

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

271
    $user_skip_query = /** @scrutinizer ignore-deprecated */ db_user_list($user_skip_list);
Loading history...
272
    if (!empty($user_skip_query)) {
273
      foreach ($user_skip_query as $user_skip_row) {
274
        $result[$user_skip_row['id']] = $user_skip_row['id'];
275
      }
276
    }
277
  }
278
279
  return $result;
280
}
281
282
function market_get_autoconvert_cost() {
283
  return SN::$config->rpg_cost_exchange ? SN::$config->rpg_cost_exchange * 3 : 3000;
284
}
285
286
/**
287
 * @param $powerup_id
288
 * @param $powerup_unit
289
 * @param $level_max
290
 * @param $plain
291
 *
292
 * @return mixed|null
293
 */
294
function sn_powerup_get_price_matrix($powerup_id, $powerup_unit = false, $level_max = null, $plain = false) {
295
  $result = null;
296
297
  /** @see sn_sn_powerup_get_price_matrix(), FestivalHighspotDiscountMatrix::sn_powerup_get_price_matrix_linear() */
298
  return sn_function_call('sn_powerup_get_price_matrix', array($powerup_id, $powerup_unit, $level_max, $plain, &$result));
299
}
300
301
/**
302
 * @param $powerup_id
303
 * @param $powerup_unit
304
 * @param $level_max
305
 * @param $plain
306
 * @param $result
307
 *
308
 * @return array
309
 *
310
 * @see sn_powerup_get_price_matrix()
311
 */
312
function sn_sn_powerup_get_price_matrix($powerup_id, $powerup_unit = false, $level_max = null, $plain = false, &$result) {
313
  global $sn_powerup_buy_discounts;
314
315
  $result = array();
316
317
  $powerup_data = get_unit_param($powerup_id);
318
  $is_upgrade   = !empty($powerup_unit) && $powerup_unit;
319
320
  $level_current = $term_original = $time_left = 0;
321
  if ($is_upgrade) {
322
    $time_finish = strtotime($powerup_unit['unit_time_finish']);
323
    $time_left   = max(0, $time_finish - SN_TIME_NOW);
324
    if ($time_left > 0) {
325
      $term_original = $time_finish - strtotime($powerup_unit['unit_time_start']);
326
      $level_current = $powerup_unit['unit_level'];
327
    }
328
  }
329
330
  $level_max     = $level_max > $powerup_data[P_MAX_STACK] ? $level_max : $powerup_data[P_MAX_STACK];
331
  $original_cost = 0;
332
  for ($i = 1; $i <= $level_max; $i++) {
333
    $base_cost = eco_get_total_cost($powerup_id, $i);
334
    $base_cost = $base_cost[BUILD_CREATE][RES_DARK_MATTER];
335
    foreach ($sn_powerup_buy_discounts as $period => $discount) {
336
      $upgrade_price       = floor($base_cost * $discount * $period / PERIOD_MONTH);
337
      $result[$i][$period] = $upgrade_price;
338
      $original_cost       = $is_upgrade && $i == $level_current && $period <= $term_original ? $upgrade_price : $original_cost;
339
    }
340
  }
341
342
  if ($is_upgrade && $time_left) {
343
    $term_original = round($term_original / PERIOD_DAY);
344
    $time_left     = min(floor($time_left / PERIOD_DAY), $term_original);
345
    $cost_left     = $term_original > 0 ? ceil($time_left / $term_original * $original_cost) : 0;
346
347
    array_walk_recursive($result, function (&$value) use ($cost_left) {
348
      $value -= $cost_left;
349
    });
350
  }
351
352
  return $result;
353
}
354
355
/**
356
 * @param $price_matrix_plain
357
 * @param $price_matrix_original
358
 * @param $price_matrix_upgrade
359
 * @param $user_dark_matter
360
 *
361
 * @return array
362
 *
363
 * Used in player_premium and interface_batch_operation modules
364
 */
365
function price_matrix_templatize(&$price_matrix_plain, &$price_matrix_original, &$price_matrix_upgrade, $user_dark_matter) {
366
  $prices = array();
367
  foreach ($price_matrix_original as $level_num => $level_data) {
368
    $price_per_period = array();
369
    foreach ($level_data as $period => $price) {
370
      $price_per_period[$period] = array(
371
        'PERIOD'             => $period,
372
        'PRICE_ORIGIN'       => $price,
373
        'PRICE_ORIGIN_TEXT'  => HelperString::numberFloorAndFormat($price),
374
        'PRICE_ORIGIN_CLASS' => prettyNumberGetClass($price, $user_dark_matter),
375
        'PRICE_UPGRADE'      => $price_matrix_upgrade[$level_num][$period],
376
        'PRICE_UPGRADE_TEXT' => HelperString::numberFloorAndFormat($price_matrix_upgrade[$level_num][$period]),
377
      );
378
      if (isset($price_matrix_plain[$level_num][$period])) {
379
        $price_per_period[$period] += array(
380
          'PRICE_PLAIN_PERCENT' => ceil(100 - ($price / $price_matrix_plain[$level_num][$period]) * 100),
381
          'PRICE_PLAIN'         => $price_matrix_plain[$level_num][$period],
382
          'PRICE_PLAIN_TEXT'    => HelperString::numberFloorAndFormat($price_matrix_plain[$level_num][$period]),
383
        );
384
      }
385
    }
386
387
    $prices[$level_num] = array(
388
      '.'     => array('period' => $price_per_period),
389
      'LEVEL' => $level_num,
390
    );
391
  }
392
393
  return $prices;
394
}
395
396
397
// TOOLS & UTILITIES ----------------------------------------------------------------------------------------------------------------
398
/**
399
 * Generates random string of $length symbols from $allowed_chars charset
400
 *
401
 * @param int    $length
402
 * @param string $allowed_chars
403
 *
404
 * @return string
405
 */
406
function sys_random_string($length = 16, $allowed_chars = SN_SYS_SEC_CHARS_ALLOWED) {
407
  $allowed_length = strlen($allowed_chars);
408
409
  $random_string = '';
410
  for ($i = 0; $i < $length; $i++) {
411
    $random_string .= $allowed_chars[mt_rand(0, $allowed_length - 1)];
412
  }
413
414
  return $random_string;
415
}
416
417
function array_merge_recursive_numeric($array1, $array2) {
418
  if (!empty($array2) && is_array($array2)) {
419
    foreach ($array2 as $key => $value) {
420
      $array1[$key] = !isset($array1[$key]) || !is_array($array1[$key]) ? $value : array_merge_recursive_numeric($array1[$key], $value);
421
    }
422
  }
423
424
  return $array1;
425
}
426
427
function sn_sys_array_cumulative_sum(&$array) {
428
  $accum = 0;
429
  foreach ($array as &$value) {
430
    $accum += $value;
431
    $value = $accum;
432
  }
433
}
434
435
function print_rr($var, $capture = false) {
436
  $print = '<pre>' . htmlspecialchars(print_r($var, true)) . '</pre>';
0 ignored issues
show
It seems like print_r($var, true) can also be of type true; however, parameter $string of htmlspecialchars() does only seem to accept string, 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

436
  $print = '<pre>' . htmlspecialchars(/** @scrutinizer ignore-type */ print_r($var, true)) . '</pre>';
Loading history...
437
  if ($capture) {
438
    return $print;
439
  } else {
440
    print($print);
441
  }
442
443
  return $print;
444
}
445
446
/**
447
 * Returns unique string ID for total fleets on planet
448
 *
449
 * @param array $planetTemplatized
450
 *
451
 * @return int|string
452
 */
453
function getUniqueFleetId($planetTemplatized) {
454
  return empty($planetTemplatized['id']) ? 0 : sprintf(FLEET_ID_TEMPLATE, $planetTemplatized['id']);
455
}
456
457
/**
458
 * @param array $context
459
 *
460
 * @return array
461
 */
462
function getLocationFromContext($context = []) {
463
  if (!empty($context[LOC_FLEET])) {
464
    return [LOC_FLEET, $context[LOC_FLEET]['fleet_id']];
465
  } elseif (!empty($context[LOC_PLANET])) {
466
    return [LOC_PLANET, $context[LOC_PLANET]['id']];
467
  } elseif (!empty($context[LOC_USER])) {
468
    return [LOC_USER, $context[LOC_USER]['id']];
469
  } else {
470
    return [LOC_SERVER, 0];
471
  }
472
473
}
474
475
476
//
477
478
479
// MAIL ----------------------------------------------------------------------------------------------------------------
480
function mymail($email_unsafe, $title, $body, $from = '', $html = false) {
481
  $from = trim($from ? $from : SN::$config->game_adminEmail);
482
483
  $head = '';
484
  $head .= "Content-Type: text/" . ($html ? 'html' : 'plain') . "; charset=utf-8 \r\n";
485
  $head .= "Date: " . date('r') . " \r\n";
486
  $head .= "Return-Path: " . SN::$config->game_adminEmail . " \r\n";
487
  $head .= "From: {$from} \r\n";
488
  $head .= "Sender: {$from} \r\n";
489
  $head .= "Reply-To: {$from} \r\n";
490
//  $head .= "Organization: {$org} \r\n";
491
  $head .= "X-Sender: {$from} \r\n";
492
  $head .= "X-Priority: 3 \r\n";
493
494
  $body = str_replace("\r\n", "\n", $body);
495
  $body = str_replace("\n", "\r\n", $body);
496
497
  if ($html) {
498
    /** @noinspection HtmlRequiredLangAttribute, HtmlRequiredTitleElement */
499
    $body = '<html><head><base href="' . SN_ROOT_VIRTUAL . '"></head><body>' . nl2br($body) . '</body></html>';
500
  }
501
502
  $title = '=?UTF-8?B?' . base64_encode($title) . '?=';
503
504
  return @mail($email_unsafe, $title, $body, $head);
505
}
506
507
508
// VERSION FUNCTIONS ----------------------------------------------------------------------------------------------------------------
509
function sn_version_compare_extra($version) {
510
  static $version_regexp = '#(\d+)([a-f])(\d+)(?:\.(\d+))*#';
511
  preg_match($version_regexp, $version, $version);
512
  unset($version[0]);
513
  $version[2] = ord($version[2]) - ord('a');
514
515
  return implode('.', $version);
516
}
517
518
function sn_version_compare($ver1, $ver2) {
519
  return version_compare(sn_version_compare_extra($ver1), sn_version_compare_extra($ver2));
520
}
521
522
523
// MODULES FUNCTIONS ---------------------------------------------------------------------------------------------------
524
/**
525
 * Return Award module or NULL
526
 *
527
 * For typecasting
528
 *
529
 * @return null|player_award|\Modules\sn_module
0 ignored issues
show
The type player_award was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
530
 */
531
function moduleAward() {
532
  return SN::$gc->modules->getModule('player_award');
533
}
534
535
/**
536
 * Return Captain module or NULL
537
 *
538
 * For typecasting
539
 *
540
 * @return null|unit_captain|\Modules\sn_module
0 ignored issues
show
The type unit_captain was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
541
 */
542
function moduleCaptain() {
543
  return SN::$gc->modules->getModule('unit_captain');
544
}
545
546
/**
547
 * Updates users online count
548
 *
549
 * We should move this to separate function due to ambiguency of pass() method
550
 *
551
 * @param $usersOnline
552
 */
553
function dbUpdateUsersOnline($usersOnline) {
554
  SN::$config->pass()->var_online_user_count = $usersOnline;
555
}
556
557
/**
558
 * Updates total user count
559
 *
560
 * We should move this to separate function due to ambiguency of pass() method
561
 *
562
 * @param $userCount
563
 */
564
function dbUpdateUsersCount($userCount) {
565
  SN::$config->pass()->users_amount = $userCount;
566
}
567