1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace DBStatic; |
4
|
|
|
|
5
|
|
|
use classSupernova; |
6
|
|
|
use DbResultIterator; |
7
|
|
|
use mysqli_result; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Class DBStatic\DBStaticUser |
11
|
|
|
*/ |
12
|
|
|
class DBStaticUser { |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* @param mixed $user |
16
|
|
|
*/ |
17
|
|
|
// TODO - remove! |
18
|
|
|
public static function validateUserRecord($user) { |
19
|
|
|
if (!is_array($user)) { |
20
|
|
|
// TODO - remove later |
21
|
|
|
print('<h1>СООБЩИТЕ ЭТО АДМИНУ: sn_db_unit_changeset_prepare() - USER is not ARRAY</h1>'); |
22
|
|
|
pdump(debug_backtrace()); |
23
|
|
|
die('USER is not ARRAY'); |
24
|
|
|
} |
25
|
|
View Code Duplication |
if (!isset($user['id']) || !$user['id']) { |
|
|
|
|
26
|
|
|
// TODO - remove later |
27
|
|
|
print('<h1>СООБЩИТЕ ЭТО АДМИНУ: sn_db_unit_changeset_prepare() - USER[id] пустой</h1>'); |
28
|
|
|
pdump($user); |
29
|
|
|
pdump(debug_backtrace()); |
30
|
|
|
die('USER[id] пустой'); |
31
|
|
|
} |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @param array $playerArray |
36
|
|
|
* |
37
|
|
|
* @return string |
38
|
|
|
*/ |
39
|
|
|
// TODO - remove or use something else |
40
|
|
|
public static function renderNameAndCoordinates($playerArray) { |
41
|
|
|
return "{$playerArray['username']} " . uni_render_coordinates($playerArray); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @return DbResultIterator |
46
|
|
|
*/ |
47
|
|
|
protected static function playerSelectIterator($fields, $orderBy = '', $forUpdate = false, $groupHaving = '', $where = '', $limit = '') { |
48
|
|
|
$query = array( |
49
|
|
|
"SELECT ", |
50
|
|
|
$fields, |
51
|
|
|
" FROM `{{users}}` |
52
|
|
|
WHERE `user_as_ally` IS NULL AND `user_bot` = " . USER_BOT_PLAYER, |
53
|
|
|
); |
54
|
|
|
if ($where) { |
55
|
|
|
$query[] = " AND ({$where})"; |
56
|
|
|
} |
57
|
|
|
if ($groupHaving) { |
58
|
|
|
$query[] = " {$groupHaving}"; |
59
|
|
|
} |
60
|
|
|
if ($orderBy) { |
61
|
|
|
$query[] = " ORDER BY {$orderBy}"; |
62
|
|
|
} |
63
|
|
|
if ($limit) { |
64
|
|
|
$query[] = " LIMIT {$limit}"; |
65
|
|
|
} |
66
|
|
|
if ($forUpdate) { |
67
|
|
|
$query[] = " FOR UPDATE"; |
68
|
|
|
} |
69
|
|
|
$result = classSupernova::$db->doSelectIterator(implode('', $query)); |
70
|
|
|
|
71
|
|
|
return $result; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* @return DbResultIterator |
76
|
|
|
*/ |
77
|
|
|
public static function db_player_list_export_blitz_info() { |
78
|
|
|
return static::playerSelectIterator('`id`, `username`, `total_rank`, `total_points`, `onlinetime`', '`id` ASC'); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @return DbResultIterator |
83
|
|
|
*/ |
84
|
|
|
public static function db_user_list_non_bots() { |
85
|
|
|
return static::playerSelectIterator('`id`', '', true); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* @return DbResultIterator |
90
|
|
|
*/ |
91
|
|
|
public static function db_user_list_admin_multiaccounts() { |
92
|
|
|
return static::playerSelectIterator( |
93
|
|
|
'COUNT(`id`) AS `ip_count`, |
94
|
|
|
`user_lastip`', |
95
|
|
|
'COUNT(`id`) DESC', |
96
|
|
|
false, |
97
|
|
|
'GROUP BY `user_lastip` HAVING COUNT(`id`) > 1', |
98
|
|
|
'`user_lastip` IS NOT NULL' |
99
|
|
|
); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
// TODO - это вообще-то надо хранить в конфигурации |
103
|
|
|
/** |
104
|
|
|
* @return string |
105
|
|
|
*/ |
106
|
|
|
public static function getLastRegisteredUserName() { |
107
|
|
|
$iterator = static::playerSelectIterator('`username`', '`id` DESC', false, '', '', '1'); |
108
|
|
|
|
109
|
|
|
return classSupernova::$db->getDbIteratorFirstValue($iterator); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @param bool $online |
114
|
|
|
* |
115
|
|
|
* @return int |
116
|
|
|
*/ |
117
|
|
|
public static function db_user_count($online = false) { |
118
|
|
|
$iterator = static::playerSelectIterator('COUNT(`id`)', '', false, '', ($online ? '`onlinetime` > ' . (SN_TIME_NOW - classSupernova::$config->game_users_online_timeout) : '')); |
119
|
|
|
|
120
|
|
|
return intval(classSupernova::$db->getDbIteratorFirstValue($iterator)); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
public static function db_user_list_admin_sorted($sort, $online = false) { |
124
|
|
|
$query = "SELECT |
125
|
|
|
u.*, COUNT(r.id) AS referral_count, SUM(r.dark_matter) AS referral_dm |
126
|
|
|
FROM |
127
|
|
|
{{users}} as u |
128
|
|
|
LEFT JOIN |
129
|
|
|
{{referrals}} as r on r.id_partner = u.id |
130
|
|
|
WHERE " . |
131
|
|
|
($online ? "`onlinetime` >= " . intval(SN_TIME_NOW - classSupernova::$config->game_users_online_timeout) : 'user_as_ally IS NULL') . |
132
|
|
|
" GROUP BY u.id |
133
|
|
|
ORDER BY user_as_ally, {$sort} ASC"; |
134
|
|
|
$result = classSupernova::$db->doSelectIterator($query); |
135
|
|
|
|
136
|
|
|
return $result; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
public static function db_user_list_to_celebrate($config_user_birthday_range) { |
140
|
|
|
$query = "SELECT |
141
|
|
|
`id`, `username`, `user_birthday`, `user_birthday_celebrated`, |
142
|
|
|
CONCAT(YEAR(CURRENT_DATE), DATE_FORMAT(`user_birthday`, '-%m-%d')) AS `current_birthday`, |
143
|
|
|
DATEDIFF(CURRENT_DATE, CONCAT(YEAR(CURRENT_DATE), DATE_FORMAT(`user_birthday`, '-%m-%d'))) AS `days_after_birthday` |
144
|
|
|
FROM |
145
|
|
|
`{{users}}` |
146
|
|
|
WHERE |
147
|
|
|
`user_as_ally` IS NULL |
148
|
|
|
AND `user_bot` = " . USER_BOT_PLAYER . " |
149
|
|
|
AND `user_birthday` IS NOT NULL |
150
|
|
|
AND (`user_birthday_celebrated` IS NULL OR DATE_ADD(`user_birthday_celebrated`, INTERVAL 1 YEAR) < CURRENT_DATE) |
151
|
|
|
HAVING |
152
|
|
|
`days_after_birthday` >= 0 AND `days_after_birthday` < {$config_user_birthday_range} |
153
|
|
|
FOR UPDATE"; |
154
|
|
|
|
155
|
|
|
$result = classSupernova::$db->doSelectIterator($query); |
156
|
|
|
|
157
|
|
|
return $result; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
|
161
|
|
|
public static function lockAllRecords() { |
162
|
|
|
classSupernova::$db->doSelect("SELECT 1 FROM `{{users}}` FOR UPDATE"); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
public static function db_user_lock_with_target_owner_and_acs($user, $planet = array()) { |
166
|
|
|
$query = |
167
|
|
|
"SELECT 1 |
168
|
|
|
FROM `{{users}}` |
169
|
|
|
WHERE `id` = " . idval($user['id']) . |
170
|
|
|
(!empty($planet['id_owner']) ? ' OR `id` = ' . idval($planet['id_owner']) : '') . |
171
|
|
|
" FOR UPDATE"; |
172
|
|
|
|
173
|
|
|
classSupernova::$db->doSelect($query); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
|
177
|
|
|
public static function db_player_list_blitz_delete_players() { |
178
|
|
|
classSupernova::$db->doDeleteDanger( |
|
|
|
|
179
|
|
|
TABLE_USERS, |
180
|
|
|
array(), |
181
|
|
|
array( |
182
|
|
|
"`username` LIKE 'Игрок%'" |
183
|
|
|
) |
184
|
|
|
); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
// TODO - NEVER change DM amount directly w/o logging! |
188
|
|
|
public static function db_player_list_blitz_set_50k_dm() { |
189
|
|
|
classSupernova::$db->doUpdateTableSet( |
190
|
|
|
TABLE_USERS, |
191
|
|
|
array( |
192
|
|
|
'dark_matter' => 50000, |
193
|
|
|
'dark_matter_total' => 50000, |
194
|
|
|
) |
195
|
|
|
); |
196
|
|
|
|
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Выбирает записи игроков по списку их ID |
201
|
|
|
* |
202
|
|
|
* @param $user_id_list |
203
|
|
|
* |
204
|
|
|
* @return array |
205
|
|
|
*/ |
206
|
|
|
public static function db_user_list_by_id($user_id_list) { |
207
|
|
|
!is_array($user_id_list) ? $user_id_list = array($user_id_list) : false; |
208
|
|
|
|
209
|
|
|
$user_list = array(); |
210
|
|
|
foreach ($user_id_list as $user_id_unsafe) { |
211
|
|
|
$user = DBStaticUser::db_user_by_id($user_id_unsafe); |
212
|
|
|
!empty($user) ? $user_list[$user_id_unsafe] = $user : false; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
return $user_list; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
public static function db_user_by_username($username_unsafe, $for_update = false, $fields = '*', $player = null, $like = false) { |
|
|
|
|
219
|
|
|
// TODO Проверить, кстати - а везде ли нужно выбирать юзеров или где-то все-таки ищутся Альянсы ? |
220
|
|
|
if (!($username_unsafe = trim($username_unsafe))) { |
221
|
|
|
return false; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
$user = null; |
225
|
|
|
if (classSupernova::$gc->snCache->isArrayLocation(LOC_USER)) { |
|
|
|
|
226
|
|
|
foreach (classSupernova::$gc->snCache->getData(LOC_USER) as $user_id => $user_data) { |
|
|
|
|
227
|
|
|
if (is_array($user_data) && isset($user_data['username'])) { |
228
|
|
|
// проверяем поле |
229
|
|
|
// TODO Возможно есть смысл всегда искать по strtolower - но может игрок захочет переименоваться с другим регистром? Проверить! |
230
|
|
|
if ((!$like && $user_data['username'] == $username_unsafe) || ($like && strtolower($user_data['username']) == strtolower($username_unsafe))) { |
231
|
|
|
$user_as_ally = idval($user_data['user_as_ally']); |
232
|
|
|
if ($player === null || ($player === true && !$user_as_ally) || ($player === false && $user_as_ally)) { |
233
|
|
|
$user = $user_data; |
234
|
|
|
break; |
235
|
|
|
} |
236
|
|
|
} |
237
|
|
|
} |
238
|
|
|
} |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
if ($user === null) { |
242
|
|
|
// Вытаскиваем запись |
243
|
|
|
$username_safe = db_escape($like ? strtolower($username_unsafe) : $username_unsafe); // тут на самом деле strtolower() лишняя, но пусть будет |
244
|
|
|
|
245
|
|
|
$user = classSupernova::$db->doSelectFetch( |
246
|
|
|
"SELECT * FROM {{users}} WHERE `username` " . ($like ? 'LIKE' : '=') . " '{$username_safe}'" |
247
|
|
|
. " FOR UPDATE" |
248
|
|
|
); |
249
|
|
|
classSupernova::$gc->snCache->cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы |
|
|
|
|
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
return $user; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
public static function db_user_list($user_filter = '', $for_update = false, $fields = '*') { |
|
|
|
|
256
|
|
|
return classSupernova::$gc->cacheOperator->db_get_record_list(LOC_USER, $user_filter); |
|
|
|
|
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* @param $user_id |
261
|
|
|
* @param array $set |
262
|
|
|
* |
263
|
|
|
* @return array|bool|mysqli_result|null |
264
|
|
|
*/ |
265
|
|
|
public static function db_user_set_by_id($user_id, $set) { |
266
|
|
|
return classSupernova::$gc->cacheOperator->db_upd_record_by_id(LOC_USER, $user_id, $set, array()); |
|
|
|
|
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
/** |
270
|
|
|
* @param $user_id |
271
|
|
|
* @param array $set |
|
|
|
|
272
|
|
|
* @param array $adjust |
273
|
|
|
* |
274
|
|
|
* @return array|bool|mysqli_result|null |
275
|
|
|
*/ |
276
|
|
|
public static function db_user_adjust_by_id($user_id, $adjust) { |
277
|
|
|
return classSupernova::$gc->cacheOperator->db_upd_record_by_id(LOC_USER, $user_id, array(), $adjust); |
|
|
|
|
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
/** |
281
|
|
|
* Возвращает информацию о пользователе по его ID |
282
|
|
|
* |
283
|
|
|
* @param int|array $user_id_unsafe |
284
|
|
|
* <p>int - ID пользователя</p> |
285
|
|
|
* <p>array - запись пользователя с установленным полем ['id']</p> |
286
|
|
|
* @param bool $for_update @deprecated |
287
|
|
|
* @param string $fields @deprecated список полей или '*'/'' для всех полей |
288
|
|
|
* @param null $player |
289
|
|
|
* @param bool|null $player Признак выбора записи пользователь типа "игрок" |
290
|
|
|
* <p>null - Можно выбрать запись любого типа</p> |
291
|
|
|
* <p>true - Выбирается только запись типа "игрок"</p> |
292
|
|
|
* <p>false - Выбирается только запись типа "альянс"</p> |
293
|
|
|
* |
294
|
|
|
* @return array|false |
295
|
|
|
* <p>false - Нет записи с указанным ID и $player</p> |
296
|
|
|
* <p>array - запись типа $user</p> |
297
|
|
|
*/ |
298
|
|
|
public static function db_user_by_id($user_id_unsafe, $for_update = false, $fields = '*', $player = null) { |
299
|
|
|
$user = classSupernova::$gc->cacheOperator->db_get_record_by_id(LOC_USER, $user_id_unsafe, $for_update, $fields); |
|
|
|
|
300
|
|
|
|
301
|
|
|
return (is_array($user) && |
302
|
|
|
( |
303
|
|
|
$player === null |
304
|
|
|
|| |
305
|
|
|
($player === true && !$user['user_as_ally']) |
306
|
|
|
|| |
307
|
|
|
($player === false && $user['user_as_ally']) |
308
|
|
|
)) ? $user : false; |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* @param $ally_id |
313
|
|
|
* @param $ally_rank_id |
314
|
|
|
* @param array $set |
315
|
|
|
* @param array $adjust |
316
|
|
|
*/ |
317
|
|
|
public static function db_user_list_set_by_ally_and_rank($ally_id, $ally_rank_id, $set, $adjust) { |
318
|
|
|
classSupernova::$gc->cacheOperator->db_upd_record_list_DANGER( |
|
|
|
|
319
|
|
|
LOC_USER, |
320
|
|
|
$set, |
321
|
|
|
$adjust, |
322
|
|
|
array( |
323
|
|
|
'ally_id' => $ally_id, |
324
|
|
|
), |
325
|
|
|
array( |
326
|
|
|
// TODO - DANGER !!! |
327
|
|
|
"`ally_rank_id` >= {$ally_rank_id}" |
328
|
|
|
) |
329
|
|
|
); |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* @param array $playerRowFieldChanges - array of $resourceId => $amount |
334
|
|
|
* @param int $userId |
335
|
|
|
* |
336
|
|
|
* // TODO - DEDUPLICATE |
337
|
|
|
* |
338
|
|
|
* @see DBStaticPlanet::db_planet_update_resources |
339
|
|
|
*/ |
340
|
|
View Code Duplication |
public static function db_user_update_resources($playerRowFieldChanges, $userId) { |
|
|
|
|
341
|
|
|
$fields = array(); |
342
|
|
|
foreach ($playerRowFieldChanges as $resourceId => $value) { |
343
|
|
|
$fields[pname_resource_name($resourceId)] = $value; |
344
|
|
|
} |
345
|
|
|
if (!empty($fields)) { |
346
|
|
|
classSupernova::$gc->db->doUpdateRowAdjust( |
|
|
|
|
347
|
|
|
TABLE_USERS, |
348
|
|
|
array(), |
349
|
|
|
$fields, |
350
|
|
|
array( |
351
|
|
|
'id' => $userId |
352
|
|
|
) |
353
|
|
|
); |
354
|
|
|
} |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
} |
358
|
|
|
|
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.