|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* Forum maintenance. Important stuff. |
|
5
|
|
|
* |
|
6
|
|
|
* Simple Machines Forum (SMF) |
|
7
|
|
|
* |
|
8
|
|
|
* @package SMF |
|
9
|
|
|
* @author Simple Machines http://www.simplemachines.org |
|
10
|
|
|
* @copyright 2016 Simple Machines and individual contributors |
|
11
|
|
|
* @license http://www.simplemachines.org/about/smf/license.php BSD |
|
12
|
|
|
* |
|
13
|
|
|
* @version 2.1 Beta 3 |
|
14
|
|
|
*/ |
|
15
|
|
|
|
|
16
|
|
|
if (!defined('SMF')) |
|
17
|
|
|
die('No direct access...'); |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Main dispatcher, the maintenance access point. |
|
21
|
|
|
* This, as usual, checks permissions, loads language files, and forwards to the actual workers. |
|
22
|
|
|
*/ |
|
23
|
|
|
function ManageMaintenance() |
|
24
|
|
|
{ |
|
25
|
|
|
global $txt, $context; |
|
26
|
|
|
|
|
27
|
|
|
// You absolutely must be an admin by here! |
|
28
|
|
|
isAllowedTo('admin_forum'); |
|
29
|
|
|
|
|
30
|
|
|
// Need something to talk about? |
|
31
|
|
|
loadLanguage('ManageMaintenance'); |
|
32
|
|
|
loadTemplate('ManageMaintenance'); |
|
33
|
|
|
|
|
34
|
|
|
// This uses admin tabs - as it should! |
|
35
|
|
|
$context[$context['admin_menu_name']]['tab_data'] = array( |
|
36
|
|
|
'title' => $txt['maintain_title'], |
|
37
|
|
|
'description' => $txt['maintain_info'], |
|
38
|
|
|
'tabs' => array( |
|
39
|
|
|
'routine' => array(), |
|
40
|
|
|
'database' => array(), |
|
41
|
|
|
'members' => array(), |
|
42
|
|
|
'topics' => array(), |
|
43
|
|
|
), |
|
44
|
|
|
); |
|
45
|
|
|
|
|
46
|
|
|
// So many things you can do - but frankly I won't let you - just these! |
|
47
|
|
|
$subActions = array( |
|
48
|
|
|
'routine' => array( |
|
49
|
|
|
'function' => 'MaintainRoutine', |
|
50
|
|
|
'template' => 'maintain_routine', |
|
51
|
|
|
'activities' => array( |
|
52
|
|
|
'version' => 'VersionDetail', |
|
53
|
|
|
'repair' => 'MaintainFindFixErrors', |
|
54
|
|
|
'recount' => 'AdminBoardRecount', |
|
55
|
|
|
'logs' => 'MaintainEmptyUnimportantLogs', |
|
56
|
|
|
'cleancache' => 'MaintainCleanCache', |
|
57
|
|
|
), |
|
58
|
|
|
), |
|
59
|
|
|
'database' => array( |
|
60
|
|
|
'function' => 'MaintainDatabase', |
|
61
|
|
|
'template' => 'maintain_database', |
|
62
|
|
|
'activities' => array( |
|
63
|
|
|
'optimize' => 'OptimizeTables', |
|
64
|
|
|
'convertentities' => 'ConvertEntities', |
|
65
|
|
|
'convertutf8' => 'ConvertUtf8', |
|
66
|
|
|
'convertmsgbody' => 'ConvertMsgBody', |
|
67
|
|
|
), |
|
68
|
|
|
), |
|
69
|
|
|
'members' => array( |
|
70
|
|
|
'function' => 'MaintainMembers', |
|
71
|
|
|
'template' => 'maintain_members', |
|
72
|
|
|
'activities' => array( |
|
73
|
|
|
'reattribute' => 'MaintainReattributePosts', |
|
74
|
|
|
'purgeinactive' => 'MaintainPurgeInactiveMembers', |
|
75
|
|
|
'recountposts' => 'MaintainRecountPosts', |
|
76
|
|
|
), |
|
77
|
|
|
), |
|
78
|
|
|
'topics' => array( |
|
79
|
|
|
'function' => 'MaintainTopics', |
|
80
|
|
|
'template' => 'maintain_topics', |
|
81
|
|
|
'activities' => array( |
|
82
|
|
|
'massmove' => 'MaintainMassMoveTopics', |
|
83
|
|
|
'pruneold' => 'MaintainRemoveOldPosts', |
|
84
|
|
|
'olddrafts' => 'MaintainRemoveOldDrafts', |
|
85
|
|
|
), |
|
86
|
|
|
), |
|
87
|
|
|
'hooks' => array( |
|
88
|
|
|
'function' => 'list_integration_hooks', |
|
89
|
|
|
), |
|
90
|
|
|
'destroy' => array( |
|
91
|
|
|
'function' => 'Destroy', |
|
92
|
|
|
'activities' => array(), |
|
93
|
|
|
), |
|
94
|
|
|
); |
|
95
|
|
|
|
|
96
|
|
|
call_integration_hook('integrate_manage_maintenance', array(&$subActions)); |
|
97
|
|
|
|
|
98
|
|
|
// Yep, sub-action time! |
|
99
|
|
View Code Duplication |
if (isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']])) |
|
|
|
|
|
|
100
|
|
|
$subAction = $_REQUEST['sa']; |
|
101
|
|
|
else |
|
102
|
|
|
$subAction = 'routine'; |
|
103
|
|
|
|
|
104
|
|
|
// Doing something special? |
|
105
|
|
View Code Duplication |
if (isset($_REQUEST['activity']) && isset($subActions[$subAction]['activities'][$_REQUEST['activity']])) |
|
|
|
|
|
|
106
|
|
|
$activity = $_REQUEST['activity']; |
|
107
|
|
|
|
|
108
|
|
|
// Set a few things. |
|
109
|
|
|
$context['page_title'] = $txt['maintain_title']; |
|
110
|
|
|
$context['sub_action'] = $subAction; |
|
111
|
|
|
$context['sub_template'] = !empty($subActions[$subAction]['template']) ? $subActions[$subAction]['template'] : ''; |
|
112
|
|
|
|
|
113
|
|
|
// Finally fall through to what we are doing. |
|
114
|
|
|
call_helper($subActions[$subAction]['function']); |
|
115
|
|
|
|
|
116
|
|
|
// Any special activity? |
|
117
|
|
|
if (isset($activity)) |
|
118
|
|
|
call_helper($subActions[$subAction]['activities'][$activity]); |
|
119
|
|
|
|
|
120
|
|
|
//converted to UTF-8? show a small maintenance info |
|
121
|
|
View Code Duplication |
if (isset($_GET['done']) && $_GET['done'] == 'convertutf8') |
|
|
|
|
|
|
122
|
|
|
$context['maintenance_finished'] = $txt['utf8_title']; |
|
123
|
|
|
|
|
124
|
|
|
// Create a maintenance token. Kinda hard to do it any other way. |
|
125
|
|
|
createToken('admin-maint'); |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
/** |
|
129
|
|
|
* Supporting function for the database maintenance area. |
|
130
|
|
|
*/ |
|
131
|
|
|
function MaintainDatabase() |
|
132
|
|
|
{ |
|
133
|
|
|
global $context, $db_type, $db_character_set, $modSettings, $smcFunc, $txt; |
|
134
|
|
|
|
|
135
|
|
|
// Show some conversion options? |
|
136
|
|
|
$context['convert_utf8'] = ($db_type == 'mysql' || $db_type == 'mysqli') && (!isset($db_character_set) || $db_character_set !== 'utf8' || empty($modSettings['global_character_set']) || $modSettings['global_character_set'] !== 'UTF-8') && version_compare('4.1.2', preg_replace('~\-.+?$~', '', $smcFunc['db_server_info']()), '<='); |
|
137
|
|
|
$context['convert_entities'] = ($db_type == 'mysql' || $db_type == 'mysqli') && isset($db_character_set, $modSettings['global_character_set']) && $db_character_set === 'utf8' && $modSettings['global_character_set'] === 'UTF-8'; |
|
138
|
|
|
|
|
139
|
|
|
if ($db_type == 'mysql' || $db_type == 'mysqli') |
|
140
|
|
|
{ |
|
141
|
|
|
db_extend('packages'); |
|
142
|
|
|
|
|
143
|
|
|
$colData = $smcFunc['db_list_columns']('{db_prefix}messages', true); |
|
144
|
|
|
foreach ($colData as $column) |
|
145
|
|
|
if ($column['name'] == 'body') |
|
146
|
|
|
$body_type = $column['type']; |
|
147
|
|
|
|
|
148
|
|
|
$context['convert_to'] = $body_type == 'text' ? 'mediumtext' : 'text'; |
|
|
|
|
|
|
149
|
|
|
$context['convert_to_suggest'] = ($body_type != 'text' && !empty($modSettings['max_messageLength']) && $modSettings['max_messageLength'] < 65536); |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
View Code Duplication |
if (isset($_GET['done']) && $_GET['done'] == 'convertutf8') |
|
|
|
|
|
|
153
|
|
|
$context['maintenance_finished'] = $txt['utf8_title']; |
|
154
|
|
|
if (isset($_GET['done']) && $_GET['done'] == 'convertentities') |
|
155
|
|
|
$context['maintenance_finished'] = $txt['entity_convert_title']; |
|
156
|
|
|
} |
|
157
|
|
|
|
|
158
|
|
|
/** |
|
159
|
|
|
* Supporting function for the routine maintenance area. |
|
160
|
|
|
*/ |
|
161
|
|
|
function MaintainRoutine() |
|
162
|
|
|
{ |
|
163
|
|
|
global $context, $txt; |
|
164
|
|
|
|
|
165
|
|
|
if (isset($_GET['done']) && $_GET['done'] == 'recount') |
|
166
|
|
|
$context['maintenance_finished'] = $txt['maintain_recount']; |
|
167
|
|
|
} |
|
168
|
|
|
|
|
169
|
|
|
/** |
|
170
|
|
|
* Supporting function for the members maintenance area. |
|
171
|
|
|
*/ |
|
172
|
|
|
function MaintainMembers() |
|
173
|
|
|
{ |
|
174
|
|
|
global $context, $smcFunc, $txt; |
|
175
|
|
|
|
|
176
|
|
|
// Get membergroups - for deleting members and the like. |
|
177
|
|
|
$result = $smcFunc['db_query']('', ' |
|
178
|
|
|
SELECT id_group, group_name |
|
179
|
|
|
FROM {db_prefix}membergroups', |
|
180
|
|
|
array( |
|
181
|
|
|
) |
|
182
|
|
|
); |
|
183
|
|
|
$context['membergroups'] = array( |
|
184
|
|
|
array( |
|
185
|
|
|
'id' => 0, |
|
186
|
|
|
'name' => $txt['maintain_members_ungrouped'] |
|
187
|
|
|
), |
|
188
|
|
|
); |
|
189
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($result)) |
|
190
|
|
|
{ |
|
191
|
|
|
$context['membergroups'][] = array( |
|
192
|
|
|
'id' => $row['id_group'], |
|
193
|
|
|
'name' => $row['group_name'] |
|
194
|
|
|
); |
|
195
|
|
|
} |
|
196
|
|
|
$smcFunc['db_free_result']($result); |
|
197
|
|
|
|
|
198
|
|
|
if (isset($_GET['done']) && $_GET['done'] == 'recountposts') |
|
199
|
|
|
$context['maintenance_finished'] = $txt['maintain_recountposts']; |
|
200
|
|
|
|
|
201
|
|
|
loadJavaScriptFile('suggest.js', array('defer' => false), 'smf_suggest'); |
|
202
|
|
|
} |
|
203
|
|
|
|
|
204
|
|
|
/** |
|
205
|
|
|
* Supporting function for the topics maintenance area. |
|
206
|
|
|
*/ |
|
207
|
|
|
function MaintainTopics() |
|
208
|
|
|
{ |
|
209
|
|
|
global $context, $smcFunc, $txt, $sourcedir; |
|
210
|
|
|
|
|
211
|
|
|
// Let's load up the boards in case they are useful. |
|
212
|
|
|
$result = $smcFunc['db_query']('order_by_board_order', ' |
|
213
|
|
|
SELECT b.id_board, b.name, b.child_level, c.name AS cat_name, c.id_cat |
|
214
|
|
|
FROM {db_prefix}boards AS b |
|
215
|
|
|
LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) |
|
216
|
|
|
WHERE {query_see_board} |
|
217
|
|
|
AND redirect = {string:blank_redirect}', |
|
218
|
|
|
array( |
|
219
|
|
|
'blank_redirect' => '', |
|
220
|
|
|
) |
|
221
|
|
|
); |
|
222
|
|
|
$context['categories'] = array(); |
|
223
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($result)) |
|
224
|
|
|
{ |
|
225
|
|
|
if (!isset($context['categories'][$row['id_cat']])) |
|
226
|
|
|
$context['categories'][$row['id_cat']] = array( |
|
227
|
|
|
'name' => $row['cat_name'], |
|
228
|
|
|
'boards' => array() |
|
229
|
|
|
); |
|
230
|
|
|
|
|
231
|
|
|
$context['categories'][$row['id_cat']]['boards'][$row['id_board']] = array( |
|
232
|
|
|
'id' => $row['id_board'], |
|
233
|
|
|
'name' => $row['name'], |
|
234
|
|
|
'child_level' => $row['child_level'] |
|
235
|
|
|
); |
|
236
|
|
|
} |
|
237
|
|
|
$smcFunc['db_free_result']($result); |
|
238
|
|
|
|
|
239
|
|
|
require_once($sourcedir . '/Subs-Boards.php'); |
|
240
|
|
|
sortCategories($context['categories']); |
|
241
|
|
|
|
|
242
|
|
|
if (isset($_GET['done']) && $_GET['done'] == 'purgeold') |
|
243
|
|
|
$context['maintenance_finished'] = $txt['maintain_old']; |
|
244
|
|
|
elseif (isset($_GET['done']) && $_GET['done'] == 'massmove') |
|
245
|
|
|
$context['maintenance_finished'] = $txt['move_topics_maintenance']; |
|
246
|
|
|
} |
|
247
|
|
|
|
|
248
|
|
|
/** |
|
249
|
|
|
* Find and fix all errors on the forum. |
|
250
|
|
|
*/ |
|
251
|
|
|
function MaintainFindFixErrors() |
|
252
|
|
|
{ |
|
253
|
|
|
global $sourcedir; |
|
254
|
|
|
|
|
255
|
|
|
// Honestly, this should be done in the sub function. |
|
256
|
|
|
validateToken('admin-maint'); |
|
257
|
|
|
|
|
258
|
|
|
require_once($sourcedir . '/RepairBoards.php'); |
|
259
|
|
|
RepairBoards(); |
|
260
|
|
|
} |
|
261
|
|
|
|
|
262
|
|
|
/** |
|
263
|
|
|
* Wipes the whole cache directory. |
|
264
|
|
|
* This only applies to SMF's own cache directory, though. |
|
265
|
|
|
*/ |
|
266
|
|
|
function MaintainCleanCache() |
|
267
|
|
|
{ |
|
268
|
|
|
global $context, $txt; |
|
269
|
|
|
|
|
270
|
|
|
checkSession(); |
|
271
|
|
|
validateToken('admin-maint'); |
|
272
|
|
|
|
|
273
|
|
|
// Just wipe the whole cache directory! |
|
274
|
|
|
clean_cache(); |
|
275
|
|
|
|
|
276
|
|
|
$context['maintenance_finished'] = $txt['maintain_cache']; |
|
277
|
|
|
} |
|
278
|
|
|
|
|
279
|
|
|
/** |
|
280
|
|
|
* Empties all uninmportant logs |
|
281
|
|
|
*/ |
|
282
|
|
|
function MaintainEmptyUnimportantLogs() |
|
283
|
|
|
{ |
|
284
|
|
|
global $context, $smcFunc, $txt; |
|
285
|
|
|
|
|
286
|
|
|
checkSession(); |
|
287
|
|
|
validateToken('admin-maint'); |
|
288
|
|
|
|
|
289
|
|
|
// No one's online now.... MUHAHAHAHA :P. |
|
290
|
|
|
$smcFunc['db_query']('', ' |
|
291
|
|
|
DELETE FROM {db_prefix}log_online'); |
|
292
|
|
|
|
|
293
|
|
|
// Dump the banning logs. |
|
294
|
|
|
$smcFunc['db_query']('', ' |
|
295
|
|
|
DELETE FROM {db_prefix}log_banned'); |
|
296
|
|
|
|
|
297
|
|
|
// Start id_error back at 0 and dump the error log. |
|
298
|
|
|
$smcFunc['db_query']('truncate_table', ' |
|
299
|
|
|
TRUNCATE {db_prefix}log_errors'); |
|
300
|
|
|
|
|
301
|
|
|
// Clear out the spam log. |
|
302
|
|
|
$smcFunc['db_query']('', ' |
|
303
|
|
|
DELETE FROM {db_prefix}log_floodcontrol'); |
|
304
|
|
|
|
|
305
|
|
|
// Last but not least, the search logs! |
|
306
|
|
|
$smcFunc['db_query']('truncate_table', ' |
|
307
|
|
|
TRUNCATE {db_prefix}log_search_topics'); |
|
308
|
|
|
|
|
309
|
|
|
$smcFunc['db_query']('truncate_table', ' |
|
310
|
|
|
TRUNCATE {db_prefix}log_search_messages'); |
|
311
|
|
|
|
|
312
|
|
|
$smcFunc['db_query']('truncate_table', ' |
|
313
|
|
|
TRUNCATE {db_prefix}log_search_results'); |
|
314
|
|
|
|
|
315
|
|
|
updateSettings(array('search_pointer' => 0)); |
|
316
|
|
|
|
|
317
|
|
|
$context['maintenance_finished'] = $txt['maintain_logs']; |
|
318
|
|
|
} |
|
319
|
|
|
|
|
320
|
|
|
/** |
|
321
|
|
|
* Oh noes! I'd document this but that would give it away |
|
322
|
|
|
*/ |
|
323
|
|
|
function Destroy() |
|
324
|
|
|
{ |
|
325
|
|
|
global $context; |
|
326
|
|
|
|
|
327
|
|
|
echo '<!DOCTYPE html> |
|
328
|
|
|
<html', $context['right_to_left'] ? ' dir="rtl"' : '', '><head><title>', $context['forum_name_html_safe'], ' deleted!</title></head> |
|
329
|
|
|
<body style="background-color: orange; font-family: arial, sans-serif; text-align: center;"> |
|
330
|
|
|
<div style="margin-top: 8%; font-size: 400%; color: black;">Oh my, you killed ', $context['forum_name_html_safe'], '!</div> |
|
331
|
|
|
<div style="margin-top: 7%; font-size: 500%; color: red;"><strong>You lazy bum!</strong></div> |
|
332
|
|
|
</body></html>'; |
|
333
|
|
|
obExit(false); |
|
334
|
|
|
} |
|
335
|
|
|
|
|
336
|
|
|
/** |
|
337
|
|
|
* Convert the column "body" of the table {db_prefix}messages from TEXT to MEDIUMTEXT and vice versa. |
|
338
|
|
|
* It requires the admin_forum permission. |
|
339
|
|
|
* This is needed only for MySQL. |
|
340
|
|
|
* During the conversion from MEDIUMTEXT to TEXT it check if any of the posts exceed the TEXT length and if so it aborts. |
|
341
|
|
|
* This action is linked from the maintenance screen (if it's applicable). |
|
342
|
|
|
* Accessed by ?action=admin;area=maintain;sa=database;activity=convertmsgbody. |
|
343
|
|
|
* |
|
344
|
|
|
* @uses the convert_msgbody sub template of the Admin template. |
|
345
|
|
|
*/ |
|
346
|
|
|
function ConvertMsgBody() |
|
347
|
|
|
{ |
|
348
|
|
|
global $scripturl, $context, $txt, $db_type; |
|
349
|
|
|
global $modSettings, $smcFunc, $time_start; |
|
350
|
|
|
|
|
351
|
|
|
// Show me your badge! |
|
352
|
|
|
isAllowedTo('admin_forum'); |
|
353
|
|
|
|
|
354
|
|
|
if ($db_type != 'mysql' && $db_type != 'mysqli') |
|
355
|
|
|
return; |
|
356
|
|
|
|
|
357
|
|
|
db_extend('packages'); |
|
358
|
|
|
|
|
359
|
|
|
$colData = $smcFunc['db_list_columns']('{db_prefix}messages', true); |
|
360
|
|
|
foreach ($colData as $column) |
|
361
|
|
|
if ($column['name'] == 'body') |
|
362
|
|
|
$body_type = $column['type']; |
|
363
|
|
|
|
|
364
|
|
|
$context['convert_to'] = $body_type == 'text' ? 'mediumtext' : 'text'; |
|
|
|
|
|
|
365
|
|
|
|
|
366
|
|
|
if ($body_type == 'text' || ($body_type != 'text' && isset($_POST['do_conversion']))) |
|
367
|
|
|
{ |
|
368
|
|
|
checkSession(); |
|
369
|
|
|
validateToken('admin-maint'); |
|
370
|
|
|
|
|
371
|
|
|
// Make it longer so we can do their limit. |
|
372
|
|
|
if ($body_type == 'text') |
|
373
|
|
|
$smcFunc['db_change_column']('{db_prefix}messages', 'body', array('type' => 'mediumtext')); |
|
374
|
|
|
// Shorten the column so we can have a bit (literally per record) less space occupied |
|
375
|
|
|
else |
|
376
|
|
|
$smcFunc['db_change_column']('{db_prefix}messages', 'body', array('type' => 'text')); |
|
377
|
|
|
|
|
378
|
|
|
// 3rd party integrations may be interested in knowning about this. |
|
379
|
|
|
call_integration_hook('integrate_convert_msgbody', array($body_type)); |
|
380
|
|
|
|
|
381
|
|
|
$colData = $smcFunc['db_list_columns']('{db_prefix}messages', true); |
|
382
|
|
|
foreach ($colData as $column) |
|
383
|
|
|
if ($column['name'] == 'body') |
|
384
|
|
|
$body_type = $column['type']; |
|
385
|
|
|
|
|
386
|
|
|
$context['maintenance_finished'] = $txt[$context['convert_to'] . '_title']; |
|
387
|
|
|
$context['convert_to'] = $body_type == 'text' ? 'mediumtext' : 'text'; |
|
388
|
|
|
$context['convert_to_suggest'] = ($body_type != 'text' && !empty($modSettings['max_messageLength']) && $modSettings['max_messageLength'] < 65536); |
|
389
|
|
|
|
|
390
|
|
|
return; |
|
391
|
|
|
redirectexit('action=admin;area=maintain;sa=database'); |
|
|
|
|
|
|
392
|
|
|
} |
|
393
|
|
|
elseif ($body_type != 'text' && (!isset($_POST['do_conversion']) || isset($_POST['cont']))) |
|
394
|
|
|
{ |
|
395
|
|
|
checkSession(); |
|
396
|
|
|
if (empty($_REQUEST['start'])) |
|
397
|
|
|
validateToken('admin-maint'); |
|
398
|
|
|
else |
|
399
|
|
|
validateToken('admin-convertMsg'); |
|
400
|
|
|
|
|
401
|
|
|
$context['page_title'] = $txt['not_done_title']; |
|
402
|
|
|
$context['continue_post_data'] = ''; |
|
403
|
|
|
$context['continue_countdown'] = 3; |
|
404
|
|
|
$context['sub_template'] = 'not_done'; |
|
405
|
|
|
$increment = 500; |
|
406
|
|
|
$id_msg_exceeding = isset($_POST['id_msg_exceeding']) ? explode(',', $_POST['id_msg_exceeding']) : array(); |
|
407
|
|
|
|
|
408
|
|
|
$request = $smcFunc['db_query']('', ' |
|
409
|
|
|
SELECT COUNT(*) as count |
|
410
|
|
|
FROM {db_prefix}messages', |
|
411
|
|
|
array() |
|
412
|
|
|
); |
|
413
|
|
|
list($max_msgs) = $smcFunc['db_fetch_row']($request); |
|
414
|
|
|
$smcFunc['db_free_result']($request); |
|
415
|
|
|
|
|
416
|
|
|
// Try for as much time as possible. |
|
417
|
|
|
@set_time_limit(600); |
|
|
|
|
|
|
418
|
|
|
|
|
419
|
|
|
while ($_REQUEST['start'] < $max_msgs) |
|
420
|
|
|
{ |
|
421
|
|
|
$request = $smcFunc['db_query']('', ' |
|
422
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ id_msg |
|
423
|
|
|
FROM {db_prefix}messages |
|
424
|
|
|
WHERE id_msg BETWEEN {int:start} AND {int:start} + {int:increment} |
|
425
|
|
|
AND LENGTH(body) > 65535', |
|
426
|
|
|
array( |
|
427
|
|
|
'start' => $_REQUEST['start'], |
|
428
|
|
|
'increment' => $increment - 1, |
|
429
|
|
|
) |
|
430
|
|
|
); |
|
431
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
432
|
|
|
$id_msg_exceeding[] = $row['id_msg']; |
|
433
|
|
|
$smcFunc['db_free_result']($request); |
|
434
|
|
|
|
|
435
|
|
|
$_REQUEST['start'] += $increment; |
|
436
|
|
|
|
|
437
|
|
|
if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 3) |
|
438
|
|
|
{ |
|
439
|
|
|
createToken('admin-convertMsg'); |
|
440
|
|
|
$context['continue_post_data'] = ' |
|
441
|
|
|
<input type="hidden" name="' . $context['admin-convertMsg_token_var'] . '" value="' . $context['admin-convertMsg_token'] . '"> |
|
442
|
|
|
<input type="hidden" name="' . $context['session_var'] . '" value="' . $context['session_id'] . '"> |
|
443
|
|
|
<input type="hidden" name="id_msg_exceeding" value="' . implode(',', $id_msg_exceeding) . '">'; |
|
444
|
|
|
|
|
445
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=database;activity=convertmsgbody;start=' . $_REQUEST['start']; |
|
446
|
|
|
$context['continue_percent'] = round(100 * $_REQUEST['start'] / $max_msgs); |
|
447
|
|
|
|
|
448
|
|
|
return; |
|
449
|
|
|
} |
|
450
|
|
|
} |
|
451
|
|
|
createToken('admin-maint'); |
|
452
|
|
|
$context['page_title'] = $txt[$context['convert_to'] . '_title']; |
|
453
|
|
|
$context['sub_template'] = 'convert_msgbody'; |
|
454
|
|
|
|
|
455
|
|
|
if (!empty($id_msg_exceeding)) |
|
456
|
|
|
{ |
|
457
|
|
|
if (count($id_msg_exceeding) > 100) |
|
458
|
|
|
{ |
|
459
|
|
|
$query_msg = array_slice($id_msg_exceeding, 0, 100); |
|
460
|
|
|
$context['exceeding_messages_morethan'] = sprintf($txt['exceeding_messages_morethan'], count($id_msg_exceeding)); |
|
461
|
|
|
} |
|
462
|
|
|
else |
|
463
|
|
|
$query_msg = $id_msg_exceeding; |
|
464
|
|
|
|
|
465
|
|
|
$context['exceeding_messages'] = array(); |
|
466
|
|
|
$request = $smcFunc['db_query']('', ' |
|
467
|
|
|
SELECT id_msg, id_topic, subject |
|
468
|
|
|
FROM {db_prefix}messages |
|
469
|
|
|
WHERE id_msg IN ({array_int:messages})', |
|
470
|
|
|
array( |
|
471
|
|
|
'messages' => $query_msg, |
|
472
|
|
|
) |
|
473
|
|
|
); |
|
474
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
475
|
|
|
$context['exceeding_messages'][] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] . '">' . $row['subject'] . '</a>'; |
|
476
|
|
|
$smcFunc['db_free_result']($request); |
|
477
|
|
|
} |
|
478
|
|
|
} |
|
479
|
|
|
} |
|
480
|
|
|
|
|
481
|
|
|
/** |
|
482
|
|
|
* Converts HTML-entities to their UTF-8 character equivalents. |
|
483
|
|
|
* This requires the admin_forum permission. |
|
484
|
|
|
* Pre-condition: UTF-8 has been set as database and global character set. |
|
485
|
|
|
* |
|
486
|
|
|
* It is divided in steps of 10 seconds. |
|
487
|
|
|
* This action is linked from the maintenance screen (if applicable). |
|
488
|
|
|
* It is accessed by ?action=admin;area=maintain;sa=database;activity=convertentities. |
|
489
|
|
|
* |
|
490
|
|
|
* @uses Admin template, convert_entities sub-template. |
|
491
|
|
|
*/ |
|
492
|
|
|
function ConvertEntities() |
|
493
|
|
|
{ |
|
494
|
|
|
global $db_character_set, $modSettings, $context, $sourcedir, $smcFunc; |
|
495
|
|
|
|
|
496
|
|
|
isAllowedTo('admin_forum'); |
|
497
|
|
|
|
|
498
|
|
|
// Check to see if UTF-8 is currently the default character set. |
|
499
|
|
|
if ($modSettings['global_character_set'] !== 'UTF-8' || !isset($db_character_set) || $db_character_set !== 'utf8') |
|
500
|
|
|
fatal_lang_error('entity_convert_only_utf8'); |
|
501
|
|
|
|
|
502
|
|
|
// Some starting values. |
|
503
|
|
|
$context['table'] = empty($_REQUEST['table']) ? 0 : (int) $_REQUEST['table']; |
|
504
|
|
|
$context['start'] = empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start']; |
|
505
|
|
|
|
|
506
|
|
|
$context['start_time'] = time(); |
|
507
|
|
|
|
|
508
|
|
|
$context['first_step'] = !isset($_REQUEST[$context['session_var']]); |
|
509
|
|
|
$context['last_step'] = false; |
|
510
|
|
|
|
|
511
|
|
|
// The first step is just a text screen with some explanation. |
|
512
|
|
|
if ($context['first_step']) |
|
513
|
|
|
{ |
|
514
|
|
|
validateToken('admin-maint'); |
|
515
|
|
|
createToken('admin-maint'); |
|
516
|
|
|
|
|
517
|
|
|
$context['sub_template'] = 'convert_entities'; |
|
518
|
|
|
return; |
|
519
|
|
|
} |
|
520
|
|
|
// Otherwise use the generic "not done" template. |
|
521
|
|
|
$context['sub_template'] = 'not_done'; |
|
522
|
|
|
$context['continue_post_data'] = ''; |
|
523
|
|
|
$context['continue_countdown'] = 3; |
|
524
|
|
|
|
|
525
|
|
|
// Now we're actually going to convert... |
|
526
|
|
|
checkSession('request'); |
|
527
|
|
|
validateToken('admin-maint'); |
|
528
|
|
|
createToken('admin-maint'); |
|
529
|
|
|
|
|
530
|
|
|
// A list of tables ready for conversion. |
|
531
|
|
|
$tables = array( |
|
532
|
|
|
'ban_groups', |
|
533
|
|
|
'ban_items', |
|
534
|
|
|
'boards', |
|
535
|
|
|
'calendar', |
|
536
|
|
|
'calendar_holidays', |
|
537
|
|
|
'categories', |
|
538
|
|
|
'log_errors', |
|
539
|
|
|
'log_search_subjects', |
|
540
|
|
|
'membergroups', |
|
541
|
|
|
'members', |
|
542
|
|
|
'message_icons', |
|
543
|
|
|
'messages', |
|
544
|
|
|
'package_servers', |
|
545
|
|
|
'personal_messages', |
|
546
|
|
|
'pm_recipients', |
|
547
|
|
|
'polls', |
|
548
|
|
|
'poll_choices', |
|
549
|
|
|
'smileys', |
|
550
|
|
|
'themes', |
|
551
|
|
|
); |
|
552
|
|
|
$context['num_tables'] = count($tables); |
|
553
|
|
|
|
|
554
|
|
|
// Loop through all tables that need converting. |
|
555
|
|
|
for (; $context['table'] < $context['num_tables']; $context['table']++) |
|
556
|
|
|
{ |
|
557
|
|
|
$cur_table = $tables[$context['table']]; |
|
558
|
|
|
$primary_key = ''; |
|
559
|
|
|
// Make sure we keep stuff unique! |
|
560
|
|
|
$primary_keys = array(); |
|
561
|
|
|
|
|
562
|
|
|
if (function_exists('apache_reset_timeout')) |
|
563
|
|
|
@apache_reset_timeout(); |
|
|
|
|
|
|
564
|
|
|
|
|
565
|
|
|
// Get a list of text columns. |
|
566
|
|
|
$columns = array(); |
|
567
|
|
|
$request = $smcFunc['db_query']('', ' |
|
568
|
|
|
SHOW FULL COLUMNS |
|
569
|
|
|
FROM {db_prefix}{raw:cur_table}', |
|
570
|
|
|
array( |
|
571
|
|
|
'cur_table' => $cur_table, |
|
572
|
|
|
) |
|
573
|
|
|
); |
|
574
|
|
|
while ($column_info = $smcFunc['db_fetch_assoc']($request)) |
|
575
|
|
|
if (strpos($column_info['Type'], 'text') !== false || strpos($column_info['Type'], 'char') !== false) |
|
576
|
|
|
$columns[] = strtolower($column_info['Field']); |
|
577
|
|
|
|
|
578
|
|
|
// Get the column with the (first) primary key. |
|
579
|
|
|
$request = $smcFunc['db_query']('', ' |
|
580
|
|
|
SHOW KEYS |
|
581
|
|
|
FROM {db_prefix}{raw:cur_table}', |
|
582
|
|
|
array( |
|
583
|
|
|
'cur_table' => $cur_table, |
|
584
|
|
|
) |
|
585
|
|
|
); |
|
586
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
587
|
|
|
{ |
|
588
|
|
|
if ($row['Key_name'] === 'PRIMARY') |
|
589
|
|
|
{ |
|
590
|
|
|
if (empty($primary_key) || ($row['Seq_in_index'] == 1 && !in_array(strtolower($row['Column_name']), $columns))) |
|
591
|
|
|
$primary_key = $row['Column_name']; |
|
592
|
|
|
|
|
593
|
|
|
$primary_keys[] = $row['Column_name']; |
|
594
|
|
|
} |
|
595
|
|
|
} |
|
596
|
|
|
$smcFunc['db_free_result']($request); |
|
597
|
|
|
|
|
598
|
|
|
// No primary key, no glory. |
|
599
|
|
|
// Same for columns. Just to be sure we've work to do! |
|
600
|
|
|
if (empty($primary_key) || empty($columns)) |
|
601
|
|
|
continue; |
|
602
|
|
|
|
|
603
|
|
|
// Get the maximum value for the primary key. |
|
604
|
|
|
$request = $smcFunc['db_query']('', ' |
|
605
|
|
|
SELECT MAX({identifier:key}) |
|
606
|
|
|
FROM {db_prefix}{raw:cur_table}', |
|
607
|
|
|
array( |
|
608
|
|
|
'key' => $primary_key, |
|
609
|
|
|
'cur_table' => $cur_table, |
|
610
|
|
|
) |
|
611
|
|
|
); |
|
612
|
|
|
list($max_value) = $smcFunc['db_fetch_row']($request); |
|
613
|
|
|
$smcFunc['db_free_result']($request); |
|
614
|
|
|
|
|
615
|
|
|
if (empty($max_value)) |
|
616
|
|
|
continue; |
|
617
|
|
|
|
|
618
|
|
|
while ($context['start'] <= $max_value) |
|
619
|
|
|
{ |
|
620
|
|
|
// Retrieve a list of rows that has at least one entity to convert. |
|
621
|
|
|
$request = $smcFunc['db_query']('', ' |
|
622
|
|
|
SELECT {raw:primary_keys}, {raw:columns} |
|
623
|
|
|
FROM {db_prefix}{raw:cur_table} |
|
624
|
|
|
WHERE {raw:primary_key} BETWEEN {int:start} AND {int:start} + 499 |
|
625
|
|
|
AND {raw:like_compare} |
|
626
|
|
|
LIMIT 500', |
|
627
|
|
|
array( |
|
628
|
|
|
'primary_keys' => implode(', ', $primary_keys), |
|
629
|
|
|
'columns' => implode(', ', $columns), |
|
630
|
|
|
'cur_table' => $cur_table, |
|
631
|
|
|
'primary_key' => $primary_key, |
|
632
|
|
|
'start' => $context['start'], |
|
633
|
|
|
'like_compare' => '(' . implode(' LIKE \'%&#%\' OR ', $columns) . ' LIKE \'%&#%\')', |
|
634
|
|
|
) |
|
635
|
|
|
); |
|
636
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
637
|
|
|
{ |
|
638
|
|
|
$insertion_variables = array(); |
|
639
|
|
|
$changes = array(); |
|
640
|
|
|
foreach ($row as $column_name => $column_value) |
|
641
|
|
|
if ($column_name !== $primary_key && strpos($column_value, '&#') !== false) |
|
642
|
|
|
{ |
|
643
|
|
|
$changes[] = $column_name . ' = {string:changes_' . $column_name . '}'; |
|
644
|
|
|
$insertion_variables['changes_' . $column_name] = preg_replace_callback('~&#(\d{1,7}|x[0-9a-fA-F]{1,6});~', 'fixchar__callback', $column_value); |
|
645
|
|
|
} |
|
646
|
|
|
|
|
647
|
|
|
$where = array(); |
|
648
|
|
|
foreach ($primary_keys as $key) |
|
649
|
|
|
{ |
|
650
|
|
|
$where[] = $key . ' = {string:where_' . $key . '}'; |
|
651
|
|
|
$insertion_variables['where_' . $key] = $row[$key]; |
|
652
|
|
|
} |
|
653
|
|
|
|
|
654
|
|
|
// Update the row. |
|
655
|
|
|
if (!empty($changes)) |
|
656
|
|
|
$smcFunc['db_query']('', ' |
|
657
|
|
|
UPDATE {db_prefix}' . $cur_table . ' |
|
658
|
|
|
SET |
|
659
|
|
|
' . implode(', |
|
660
|
|
|
', $changes) . ' |
|
661
|
|
|
WHERE ' . implode(' AND ', $where), |
|
662
|
|
|
$insertion_variables |
|
663
|
|
|
); |
|
664
|
|
|
} |
|
665
|
|
|
$smcFunc['db_free_result']($request); |
|
666
|
|
|
$context['start'] += 500; |
|
667
|
|
|
|
|
668
|
|
|
// After ten seconds interrupt. |
|
669
|
|
|
if (time() - $context['start_time'] > 10) |
|
670
|
|
|
{ |
|
671
|
|
|
// Calculate an approximation of the percentage done. |
|
672
|
|
|
$context['continue_percent'] = round(100 * ($context['table'] + ($context['start'] / $max_value)) / $context['num_tables'], 1); |
|
673
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=database;activity=convertentities;table=' . $context['table'] . ';start=' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
674
|
|
|
return; |
|
675
|
|
|
} |
|
676
|
|
|
} |
|
677
|
|
|
$context['start'] = 0; |
|
678
|
|
|
} |
|
679
|
|
|
|
|
680
|
|
|
// Make sure all serialized strings are all right. |
|
681
|
|
|
require_once($sourcedir . '/Subs-Charset.php'); |
|
682
|
|
|
fix_serialized_columns(); |
|
683
|
|
|
|
|
684
|
|
|
// If we're here, we must be done. |
|
685
|
|
|
$context['continue_percent'] = 100; |
|
686
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=database;done=convertentities'; |
|
687
|
|
|
$context['last_step'] = true; |
|
688
|
|
|
$context['continue_countdown'] = -1; |
|
689
|
|
|
} |
|
690
|
|
|
|
|
691
|
|
|
/** |
|
692
|
|
|
* Optimizes all tables in the database and lists how much was saved. |
|
693
|
|
|
* It requires the admin_forum permission. |
|
694
|
|
|
* It shows as the maintain_forum admin area. |
|
695
|
|
|
* It is accessed from ?action=admin;area=maintain;sa=database;activity=optimize. |
|
696
|
|
|
* It also updates the optimize scheduled task such that the tables are not automatically optimized again too soon. |
|
697
|
|
|
|
|
698
|
|
|
* @uses the optimize sub template |
|
699
|
|
|
*/ |
|
700
|
|
|
function OptimizeTables() |
|
701
|
|
|
{ |
|
702
|
|
|
global $db_prefix, $txt, $context, $smcFunc, $time_start; |
|
703
|
|
|
|
|
704
|
|
|
isAllowedTo('admin_forum'); |
|
705
|
|
|
|
|
706
|
|
|
checkSession('request'); |
|
707
|
|
|
|
|
708
|
|
|
if (!isset($_SESSION['optimized_tables'])) |
|
709
|
|
|
validateToken('admin-maint'); |
|
710
|
|
|
else |
|
711
|
|
|
validateToken('admin-optimize', 'post', false); |
|
712
|
|
|
|
|
713
|
|
|
ignore_user_abort(true); |
|
714
|
|
|
db_extend(); |
|
715
|
|
|
|
|
716
|
|
|
// Start with no tables optimized. |
|
717
|
|
|
$opttab = 0; |
|
|
|
|
|
|
718
|
|
|
|
|
719
|
|
|
$context['page_title'] = $txt['database_optimize']; |
|
720
|
|
|
$context['sub_template'] = 'optimize'; |
|
721
|
|
|
$context['continue_post_data'] = ''; |
|
722
|
|
|
$context['continue_countdown'] = 3; |
|
723
|
|
|
|
|
724
|
|
|
// Only optimize the tables related to this smf install, not all the tables in the db |
|
725
|
|
|
$real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix; |
|
726
|
|
|
|
|
727
|
|
|
// Get a list of tables, as well as how many there are. |
|
728
|
|
|
$temp_tables = $smcFunc['db_list_tables'](false, $real_prefix . '%'); |
|
729
|
|
|
$tables = array(); |
|
730
|
|
|
foreach ($temp_tables as $table) |
|
731
|
|
|
$tables[] = array('table_name' => $table); |
|
732
|
|
|
|
|
733
|
|
|
// If there aren't any tables then I believe that would mean the world has exploded... |
|
734
|
|
|
$context['num_tables'] = count($tables); |
|
735
|
|
|
if ($context['num_tables'] == 0) |
|
736
|
|
|
fatal_error('You appear to be running SMF in a flat file mode... fantastic!', false); |
|
|
|
|
|
|
737
|
|
|
|
|
738
|
|
|
$_REQUEST['start'] = empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start']; |
|
739
|
|
|
|
|
740
|
|
|
// Try for extra time due to large tables. |
|
741
|
|
|
@set_time_limit(100); |
|
|
|
|
|
|
742
|
|
|
|
|
743
|
|
|
// For each table.... |
|
744
|
|
|
$_SESSION['optimized_tables'] = !empty($_SESSION['optimized_tables']) ? $_SESSION['optimized_tables'] : array(); |
|
745
|
|
|
for ($key=$_REQUEST['start']; $context['num_tables']-1; $key++) |
|
746
|
|
|
{ |
|
747
|
|
|
if (empty($tables[$key])) |
|
748
|
|
|
break; |
|
749
|
|
|
|
|
750
|
|
|
// Continue? |
|
751
|
|
|
if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 10) |
|
752
|
|
|
{ |
|
753
|
|
|
$_REQUEST['start'] = $key; |
|
754
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=database;activity=optimize;start=' . $_REQUEST['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
755
|
|
|
$context['continue_percent'] = round(100 * $_REQUEST['start'] / $context['num_tables']); |
|
756
|
|
|
$context['sub_template'] = 'not_done'; |
|
757
|
|
|
$context['page_title'] = $txt['not_done_title']; |
|
758
|
|
|
|
|
759
|
|
|
createToken('admin-optimize'); |
|
760
|
|
|
$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-optimize_token_var'] . '" value="' . $context['admin-optimize_token'] . '">'; |
|
761
|
|
|
|
|
762
|
|
|
if (function_exists('apache_reset_timeout')) |
|
763
|
|
|
apache_reset_timeout(); |
|
764
|
|
|
|
|
765
|
|
|
return; |
|
766
|
|
|
} |
|
767
|
|
|
|
|
768
|
|
|
// Optimize the table! We use backticks here because it might be a custom table. |
|
769
|
|
|
$data_freed = $smcFunc['db_optimize_table']($tables[$key]['table_name']); |
|
770
|
|
|
|
|
771
|
|
|
if ($data_freed > 0) |
|
772
|
|
|
$_SESSION['optimized_tables'][] = array( |
|
773
|
|
|
'name' => $tables[$key]['table_name'], |
|
774
|
|
|
'data_freed' => $data_freed, |
|
775
|
|
|
); |
|
776
|
|
|
} |
|
777
|
|
|
|
|
778
|
|
|
// Number of tables, etc... |
|
779
|
|
|
$txt['database_numb_tables'] = sprintf($txt['database_numb_tables'], $context['num_tables']); |
|
780
|
|
|
$context['num_tables_optimized'] = count($_SESSION['optimized_tables']); |
|
781
|
|
|
$context['optimized_tables'] = $_SESSION['optimized_tables']; |
|
782
|
|
|
unset($_SESSION['optimized_tables']); |
|
783
|
|
|
} |
|
784
|
|
|
|
|
785
|
|
|
/** |
|
786
|
|
|
* Recount many forum totals that can be recounted automatically without harm. |
|
787
|
|
|
* it requires the admin_forum permission. |
|
788
|
|
|
* It shows the maintain_forum admin area. |
|
789
|
|
|
* |
|
790
|
|
|
* Totals recounted: |
|
791
|
|
|
* - fixes for topics with wrong num_replies. |
|
792
|
|
|
* - updates for num_posts and num_topics of all boards. |
|
793
|
|
|
* - recounts instant_messages but not unread_messages. |
|
794
|
|
|
* - repairs messages pointing to boards with topics pointing to other boards. |
|
795
|
|
|
* - updates the last message posted in boards and children. |
|
796
|
|
|
* - updates member count, latest member, topic count, and message count. |
|
797
|
|
|
* |
|
798
|
|
|
* The function redirects back to ?action=admin;area=maintain when complete. |
|
799
|
|
|
* It is accessed via ?action=admin;area=maintain;sa=database;activity=recount. |
|
800
|
|
|
*/ |
|
801
|
|
|
function AdminBoardRecount() |
|
802
|
|
|
{ |
|
803
|
|
|
global $txt, $context, $modSettings, $sourcedir; |
|
804
|
|
|
global $time_start, $smcFunc; |
|
805
|
|
|
|
|
806
|
|
|
isAllowedTo('admin_forum'); |
|
807
|
|
|
checkSession('request'); |
|
808
|
|
|
|
|
809
|
|
|
// validate the request or the loop |
|
810
|
|
|
if (!isset($_REQUEST['step'])) |
|
811
|
|
|
validateToken('admin-maint'); |
|
812
|
|
|
else |
|
813
|
|
|
validateToken('admin-boardrecount'); |
|
814
|
|
|
|
|
815
|
|
|
$context['page_title'] = $txt['not_done_title']; |
|
816
|
|
|
$context['continue_post_data'] = ''; |
|
817
|
|
|
$context['continue_countdown'] = 3; |
|
818
|
|
|
$context['sub_template'] = 'not_done'; |
|
819
|
|
|
|
|
820
|
|
|
// Try for as much time as possible. |
|
821
|
|
|
@set_time_limit(600); |
|
|
|
|
|
|
822
|
|
|
|
|
823
|
|
|
// Step the number of topics at a time so things don't time out... |
|
824
|
|
|
$request = $smcFunc['db_query']('', ' |
|
825
|
|
|
SELECT MAX(id_topic) |
|
826
|
|
|
FROM {db_prefix}topics', |
|
827
|
|
|
array( |
|
828
|
|
|
) |
|
829
|
|
|
); |
|
830
|
|
|
list ($max_topics) = $smcFunc['db_fetch_row']($request); |
|
831
|
|
|
$smcFunc['db_free_result']($request); |
|
832
|
|
|
|
|
833
|
|
|
$increment = min(max(50, ceil($max_topics / 4)), 2000); |
|
834
|
|
|
if (empty($_REQUEST['start'])) |
|
835
|
|
|
$_REQUEST['start'] = 0; |
|
836
|
|
|
|
|
837
|
|
|
$total_steps = 8; |
|
838
|
|
|
|
|
839
|
|
|
// Get each topic with a wrong reply count and fix it - let's just do some at a time, though. |
|
840
|
|
|
if (empty($_REQUEST['step'])) |
|
841
|
|
|
{ |
|
842
|
|
|
$_REQUEST['step'] = 0; |
|
843
|
|
|
|
|
844
|
|
|
while ($_REQUEST['start'] < $max_topics) |
|
845
|
|
|
{ |
|
846
|
|
|
// Recount approved messages |
|
847
|
|
|
$request = $smcFunc['db_query']('', ' |
|
848
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ t.id_topic, MAX(t.num_replies) AS num_replies, |
|
849
|
|
|
CASE WHEN COUNT(ma.id_msg) >= 1 THEN COUNT(ma.id_msg) - 1 ELSE 0 END AS real_num_replies |
|
850
|
|
|
FROM {db_prefix}topics AS t |
|
851
|
|
|
LEFT JOIN {db_prefix}messages AS ma ON (ma.id_topic = t.id_topic AND ma.approved = {int:is_approved}) |
|
852
|
|
|
WHERE t.id_topic > {int:start} |
|
853
|
|
|
AND t.id_topic <= {int:max_id} |
|
854
|
|
|
GROUP BY t.id_topic |
|
855
|
|
|
HAVING CASE WHEN COUNT(ma.id_msg) >= 1 THEN COUNT(ma.id_msg) - 1 ELSE 0 END != MAX(t.num_replies)', |
|
856
|
|
|
array( |
|
857
|
|
|
'is_approved' => 1, |
|
858
|
|
|
'start' => $_REQUEST['start'], |
|
859
|
|
|
'max_id' => $_REQUEST['start'] + $increment, |
|
860
|
|
|
) |
|
861
|
|
|
); |
|
862
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
863
|
|
|
$smcFunc['db_query']('', ' |
|
864
|
|
|
UPDATE {db_prefix}topics |
|
865
|
|
|
SET num_replies = {int:num_replies} |
|
866
|
|
|
WHERE id_topic = {int:id_topic}', |
|
867
|
|
|
array( |
|
868
|
|
|
'num_replies' => $row['real_num_replies'], |
|
869
|
|
|
'id_topic' => $row['id_topic'], |
|
870
|
|
|
) |
|
871
|
|
|
); |
|
872
|
|
|
$smcFunc['db_free_result']($request); |
|
873
|
|
|
|
|
874
|
|
|
// Recount unapproved messages |
|
875
|
|
|
$request = $smcFunc['db_query']('', ' |
|
876
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ t.id_topic, MAX(t.unapproved_posts) AS unapproved_posts, |
|
877
|
|
|
COUNT(mu.id_msg) AS real_unapproved_posts |
|
878
|
|
|
FROM {db_prefix}topics AS t |
|
879
|
|
|
LEFT JOIN {db_prefix}messages AS mu ON (mu.id_topic = t.id_topic AND mu.approved = {int:not_approved}) |
|
880
|
|
|
WHERE t.id_topic > {int:start} |
|
881
|
|
|
AND t.id_topic <= {int:max_id} |
|
882
|
|
|
GROUP BY t.id_topic |
|
883
|
|
|
HAVING COUNT(mu.id_msg) != MAX(t.unapproved_posts)', |
|
884
|
|
|
array( |
|
885
|
|
|
'not_approved' => 0, |
|
886
|
|
|
'start' => $_REQUEST['start'], |
|
887
|
|
|
'max_id' => $_REQUEST['start'] + $increment, |
|
888
|
|
|
) |
|
889
|
|
|
); |
|
890
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
891
|
|
|
$smcFunc['db_query']('', ' |
|
892
|
|
|
UPDATE {db_prefix}topics |
|
893
|
|
|
SET unapproved_posts = {int:unapproved_posts} |
|
894
|
|
|
WHERE id_topic = {int:id_topic}', |
|
895
|
|
|
array( |
|
896
|
|
|
'unapproved_posts' => $row['real_unapproved_posts'], |
|
897
|
|
|
'id_topic' => $row['id_topic'], |
|
898
|
|
|
) |
|
899
|
|
|
); |
|
900
|
|
|
$smcFunc['db_free_result']($request); |
|
901
|
|
|
|
|
902
|
|
|
$_REQUEST['start'] += $increment; |
|
903
|
|
|
|
|
904
|
|
|
if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 3) |
|
905
|
|
|
{ |
|
906
|
|
|
createToken('admin-boardrecount'); |
|
907
|
|
|
$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-boardrecount_token_var'] . '" value="' . $context['admin-boardrecount_token'] . '">'; |
|
908
|
|
|
|
|
909
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=routine;activity=recount;step=0;start=' . $_REQUEST['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
910
|
|
|
$context['continue_percent'] = round((100 * $_REQUEST['start'] / $max_topics) / $total_steps); |
|
911
|
|
|
|
|
912
|
|
|
return; |
|
913
|
|
|
} |
|
914
|
|
|
} |
|
915
|
|
|
|
|
916
|
|
|
$_REQUEST['start'] = 0; |
|
917
|
|
|
} |
|
918
|
|
|
|
|
919
|
|
|
// Update the post count of each board. |
|
920
|
|
View Code Duplication |
if ($_REQUEST['step'] <= 1) |
|
|
|
|
|
|
921
|
|
|
{ |
|
922
|
|
|
if (empty($_REQUEST['start'])) |
|
923
|
|
|
$smcFunc['db_query']('', ' |
|
924
|
|
|
UPDATE {db_prefix}boards |
|
925
|
|
|
SET num_posts = {int:num_posts} |
|
926
|
|
|
WHERE redirect = {string:redirect}', |
|
927
|
|
|
array( |
|
928
|
|
|
'num_posts' => 0, |
|
929
|
|
|
'redirect' => '', |
|
930
|
|
|
) |
|
931
|
|
|
); |
|
932
|
|
|
|
|
933
|
|
|
while ($_REQUEST['start'] < $max_topics) |
|
934
|
|
|
{ |
|
935
|
|
|
$request = $smcFunc['db_query']('', ' |
|
936
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ m.id_board, COUNT(*) AS real_num_posts |
|
937
|
|
|
FROM {db_prefix}messages AS m |
|
938
|
|
|
WHERE m.id_topic > {int:id_topic_min} |
|
939
|
|
|
AND m.id_topic <= {int:id_topic_max} |
|
940
|
|
|
AND m.approved = {int:is_approved} |
|
941
|
|
|
GROUP BY m.id_board', |
|
942
|
|
|
array( |
|
943
|
|
|
'id_topic_min' => $_REQUEST['start'], |
|
944
|
|
|
'id_topic_max' => $_REQUEST['start'] + $increment, |
|
945
|
|
|
'is_approved' => 1, |
|
946
|
|
|
) |
|
947
|
|
|
); |
|
948
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
949
|
|
|
$smcFunc['db_query']('', ' |
|
950
|
|
|
UPDATE {db_prefix}boards |
|
951
|
|
|
SET num_posts = num_posts + {int:real_num_posts} |
|
952
|
|
|
WHERE id_board = {int:id_board}', |
|
953
|
|
|
array( |
|
954
|
|
|
'id_board' => $row['id_board'], |
|
955
|
|
|
'real_num_posts' => $row['real_num_posts'], |
|
956
|
|
|
) |
|
957
|
|
|
); |
|
958
|
|
|
$smcFunc['db_free_result']($request); |
|
959
|
|
|
|
|
960
|
|
|
$_REQUEST['start'] += $increment; |
|
961
|
|
|
|
|
962
|
|
|
if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 3) |
|
963
|
|
|
{ |
|
964
|
|
|
createToken('admin-boardrecount'); |
|
965
|
|
|
$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-boardrecount_token_var'] . '" value="' . $context['admin-boardrecount_token'] . '">'; |
|
966
|
|
|
|
|
967
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=routine;activity=recount;step=1;start=' . $_REQUEST['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
968
|
|
|
$context['continue_percent'] = round((200 + 100 * $_REQUEST['start'] / $max_topics) / $total_steps); |
|
969
|
|
|
|
|
970
|
|
|
return; |
|
971
|
|
|
} |
|
972
|
|
|
} |
|
973
|
|
|
|
|
974
|
|
|
$_REQUEST['start'] = 0; |
|
975
|
|
|
} |
|
976
|
|
|
|
|
977
|
|
|
// Update the topic count of each board. |
|
978
|
|
View Code Duplication |
if ($_REQUEST['step'] <= 2) |
|
|
|
|
|
|
979
|
|
|
{ |
|
980
|
|
|
if (empty($_REQUEST['start'])) |
|
981
|
|
|
$smcFunc['db_query']('', ' |
|
982
|
|
|
UPDATE {db_prefix}boards |
|
983
|
|
|
SET num_topics = {int:num_topics}', |
|
984
|
|
|
array( |
|
985
|
|
|
'num_topics' => 0, |
|
986
|
|
|
) |
|
987
|
|
|
); |
|
988
|
|
|
|
|
989
|
|
|
while ($_REQUEST['start'] < $max_topics) |
|
990
|
|
|
{ |
|
991
|
|
|
$request = $smcFunc['db_query']('', ' |
|
992
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ t.id_board, COUNT(*) AS real_num_topics |
|
993
|
|
|
FROM {db_prefix}topics AS t |
|
994
|
|
|
WHERE t.approved = {int:is_approved} |
|
995
|
|
|
AND t.id_topic > {int:id_topic_min} |
|
996
|
|
|
AND t.id_topic <= {int:id_topic_max} |
|
997
|
|
|
GROUP BY t.id_board', |
|
998
|
|
|
array( |
|
999
|
|
|
'is_approved' => 1, |
|
1000
|
|
|
'id_topic_min' => $_REQUEST['start'], |
|
1001
|
|
|
'id_topic_max' => $_REQUEST['start'] + $increment, |
|
1002
|
|
|
) |
|
1003
|
|
|
); |
|
1004
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1005
|
|
|
$smcFunc['db_query']('', ' |
|
1006
|
|
|
UPDATE {db_prefix}boards |
|
1007
|
|
|
SET num_topics = num_topics + {int:real_num_topics} |
|
1008
|
|
|
WHERE id_board = {int:id_board}', |
|
1009
|
|
|
array( |
|
1010
|
|
|
'id_board' => $row['id_board'], |
|
1011
|
|
|
'real_num_topics' => $row['real_num_topics'], |
|
1012
|
|
|
) |
|
1013
|
|
|
); |
|
1014
|
|
|
$smcFunc['db_free_result']($request); |
|
1015
|
|
|
|
|
1016
|
|
|
$_REQUEST['start'] += $increment; |
|
1017
|
|
|
|
|
1018
|
|
|
if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 3) |
|
1019
|
|
|
{ |
|
1020
|
|
|
createToken('admin-boardrecount'); |
|
1021
|
|
|
$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-boardrecount_token_var'] . '" value="' . $context['admin-boardrecount_token'] . '">'; |
|
1022
|
|
|
|
|
1023
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=routine;activity=recount;step=2;start=' . $_REQUEST['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
1024
|
|
|
$context['continue_percent'] = round((300 + 100 * $_REQUEST['start'] / $max_topics) / $total_steps); |
|
1025
|
|
|
|
|
1026
|
|
|
return; |
|
1027
|
|
|
} |
|
1028
|
|
|
} |
|
1029
|
|
|
|
|
1030
|
|
|
$_REQUEST['start'] = 0; |
|
1031
|
|
|
} |
|
1032
|
|
|
|
|
1033
|
|
|
// Update the unapproved post count of each board. |
|
1034
|
|
View Code Duplication |
if ($_REQUEST['step'] <= 3) |
|
|
|
|
|
|
1035
|
|
|
{ |
|
1036
|
|
|
if (empty($_REQUEST['start'])) |
|
1037
|
|
|
$smcFunc['db_query']('', ' |
|
1038
|
|
|
UPDATE {db_prefix}boards |
|
1039
|
|
|
SET unapproved_posts = {int:unapproved_posts}', |
|
1040
|
|
|
array( |
|
1041
|
|
|
'unapproved_posts' => 0, |
|
1042
|
|
|
) |
|
1043
|
|
|
); |
|
1044
|
|
|
|
|
1045
|
|
|
while ($_REQUEST['start'] < $max_topics) |
|
1046
|
|
|
{ |
|
1047
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1048
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ m.id_board, COUNT(*) AS real_unapproved_posts |
|
1049
|
|
|
FROM {db_prefix}messages AS m |
|
1050
|
|
|
WHERE m.id_topic > {int:id_topic_min} |
|
1051
|
|
|
AND m.id_topic <= {int:id_topic_max} |
|
1052
|
|
|
AND m.approved = {int:is_approved} |
|
1053
|
|
|
GROUP BY m.id_board', |
|
1054
|
|
|
array( |
|
1055
|
|
|
'id_topic_min' => $_REQUEST['start'], |
|
1056
|
|
|
'id_topic_max' => $_REQUEST['start'] + $increment, |
|
1057
|
|
|
'is_approved' => 0, |
|
1058
|
|
|
) |
|
1059
|
|
|
); |
|
1060
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1061
|
|
|
$smcFunc['db_query']('', ' |
|
1062
|
|
|
UPDATE {db_prefix}boards |
|
1063
|
|
|
SET unapproved_posts = unapproved_posts + {int:unapproved_posts} |
|
1064
|
|
|
WHERE id_board = {int:id_board}', |
|
1065
|
|
|
array( |
|
1066
|
|
|
'id_board' => $row['id_board'], |
|
1067
|
|
|
'unapproved_posts' => $row['real_unapproved_posts'], |
|
1068
|
|
|
) |
|
1069
|
|
|
); |
|
1070
|
|
|
$smcFunc['db_free_result']($request); |
|
1071
|
|
|
|
|
1072
|
|
|
$_REQUEST['start'] += $increment; |
|
1073
|
|
|
|
|
1074
|
|
|
if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 3) |
|
1075
|
|
|
{ |
|
1076
|
|
|
createToken('admin-boardrecount'); |
|
1077
|
|
|
$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-boardrecount_token_var'] . '" value="' . $context['admin-boardrecount_token'] . '">'; |
|
1078
|
|
|
|
|
1079
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=routine;activity=recount;step=3;start=' . $_REQUEST['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
1080
|
|
|
$context['continue_percent'] = round((400 + 100 * $_REQUEST['start'] / $max_topics) / $total_steps); |
|
1081
|
|
|
|
|
1082
|
|
|
return; |
|
1083
|
|
|
} |
|
1084
|
|
|
} |
|
1085
|
|
|
|
|
1086
|
|
|
$_REQUEST['start'] = 0; |
|
1087
|
|
|
} |
|
1088
|
|
|
|
|
1089
|
|
|
// Update the unapproved topic count of each board. |
|
1090
|
|
View Code Duplication |
if ($_REQUEST['step'] <= 4) |
|
|
|
|
|
|
1091
|
|
|
{ |
|
1092
|
|
|
if (empty($_REQUEST['start'])) |
|
1093
|
|
|
$smcFunc['db_query']('', ' |
|
1094
|
|
|
UPDATE {db_prefix}boards |
|
1095
|
|
|
SET unapproved_topics = {int:unapproved_topics}', |
|
1096
|
|
|
array( |
|
1097
|
|
|
'unapproved_topics' => 0, |
|
1098
|
|
|
) |
|
1099
|
|
|
); |
|
1100
|
|
|
|
|
1101
|
|
|
while ($_REQUEST['start'] < $max_topics) |
|
1102
|
|
|
{ |
|
1103
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1104
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ t.id_board, COUNT(*) AS real_unapproved_topics |
|
1105
|
|
|
FROM {db_prefix}topics AS t |
|
1106
|
|
|
WHERE t.approved = {int:is_approved} |
|
1107
|
|
|
AND t.id_topic > {int:id_topic_min} |
|
1108
|
|
|
AND t.id_topic <= {int:id_topic_max} |
|
1109
|
|
|
GROUP BY t.id_board', |
|
1110
|
|
|
array( |
|
1111
|
|
|
'is_approved' => 0, |
|
1112
|
|
|
'id_topic_min' => $_REQUEST['start'], |
|
1113
|
|
|
'id_topic_max' => $_REQUEST['start'] + $increment, |
|
1114
|
|
|
) |
|
1115
|
|
|
); |
|
1116
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1117
|
|
|
$smcFunc['db_query']('', ' |
|
1118
|
|
|
UPDATE {db_prefix}boards |
|
1119
|
|
|
SET unapproved_topics = unapproved_topics + {int:real_unapproved_topics} |
|
1120
|
|
|
WHERE id_board = {int:id_board}', |
|
1121
|
|
|
array( |
|
1122
|
|
|
'id_board' => $row['id_board'], |
|
1123
|
|
|
'real_unapproved_topics' => $row['real_unapproved_topics'], |
|
1124
|
|
|
) |
|
1125
|
|
|
); |
|
1126
|
|
|
$smcFunc['db_free_result']($request); |
|
1127
|
|
|
|
|
1128
|
|
|
$_REQUEST['start'] += $increment; |
|
1129
|
|
|
|
|
1130
|
|
|
if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 3) |
|
1131
|
|
|
{ |
|
1132
|
|
|
createToken('admin-boardrecount'); |
|
1133
|
|
|
$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-boardrecount_token_var'] . '" value="' . $context['admin-boardrecount_token'] . '">'; |
|
1134
|
|
|
|
|
1135
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=routine;activity=recount;step=4;start=' . $_REQUEST['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
1136
|
|
|
$context['continue_percent'] = round((500 + 100 * $_REQUEST['start'] / $max_topics) / $total_steps); |
|
1137
|
|
|
|
|
1138
|
|
|
return; |
|
1139
|
|
|
} |
|
1140
|
|
|
} |
|
1141
|
|
|
|
|
1142
|
|
|
$_REQUEST['start'] = 0; |
|
1143
|
|
|
} |
|
1144
|
|
|
|
|
1145
|
|
|
// Get all members with wrong number of personal messages. |
|
1146
|
|
|
if ($_REQUEST['step'] <= 5) |
|
1147
|
|
|
{ |
|
1148
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1149
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ mem.id_member, COUNT(pmr.id_pm) AS real_num, |
|
1150
|
|
|
MAX(mem.instant_messages) AS instant_messages |
|
1151
|
|
|
FROM {db_prefix}members AS mem |
|
1152
|
|
|
LEFT JOIN {db_prefix}pm_recipients AS pmr ON (mem.id_member = pmr.id_member AND pmr.deleted = {int:is_not_deleted}) |
|
1153
|
|
|
GROUP BY mem.id_member |
|
1154
|
|
|
HAVING COUNT(pmr.id_pm) != MAX(mem.instant_messages)', |
|
1155
|
|
|
array( |
|
1156
|
|
|
'is_not_deleted' => 0, |
|
1157
|
|
|
) |
|
1158
|
|
|
); |
|
1159
|
|
View Code Duplication |
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
|
|
|
|
|
1160
|
|
|
updateMemberData($row['id_member'], array('instant_messages' => $row['real_num'])); |
|
1161
|
|
|
$smcFunc['db_free_result']($request); |
|
1162
|
|
|
|
|
1163
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1164
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ mem.id_member, COUNT(pmr.id_pm) AS real_num, |
|
1165
|
|
|
MAX(mem.unread_messages) AS unread_messages |
|
1166
|
|
|
FROM {db_prefix}members AS mem |
|
1167
|
|
|
LEFT JOIN {db_prefix}pm_recipients AS pmr ON (mem.id_member = pmr.id_member AND pmr.deleted = {int:is_not_deleted} AND pmr.is_read = {int:is_not_read}) |
|
1168
|
|
|
GROUP BY mem.id_member |
|
1169
|
|
|
HAVING COUNT(pmr.id_pm) != MAX(mem.unread_messages)', |
|
1170
|
|
|
array( |
|
1171
|
|
|
'is_not_deleted' => 0, |
|
1172
|
|
|
'is_not_read' => 0, |
|
1173
|
|
|
) |
|
1174
|
|
|
); |
|
1175
|
|
View Code Duplication |
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
|
|
|
|
|
1176
|
|
|
updateMemberData($row['id_member'], array('unread_messages' => $row['real_num'])); |
|
1177
|
|
|
$smcFunc['db_free_result']($request); |
|
1178
|
|
|
|
|
1179
|
|
|
if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 3) |
|
1180
|
|
|
{ |
|
1181
|
|
|
createToken('admin-boardrecount'); |
|
1182
|
|
|
$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-boardrecount_token_var'] . '" value="' . $context['admin-boardrecount_token'] . '">'; |
|
1183
|
|
|
|
|
1184
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=routine;activity=recount;step=6;start=0;' . $context['session_var'] . '=' . $context['session_id']; |
|
1185
|
|
|
$context['continue_percent'] = round(700 / $total_steps); |
|
1186
|
|
|
|
|
1187
|
|
|
return; |
|
1188
|
|
|
} |
|
1189
|
|
|
} |
|
1190
|
|
|
|
|
1191
|
|
|
// Any messages pointing to the wrong board? |
|
1192
|
|
|
if ($_REQUEST['step'] <= 6) |
|
1193
|
|
|
{ |
|
1194
|
|
|
while ($_REQUEST['start'] < $modSettings['maxMsgID']) |
|
1195
|
|
|
{ |
|
1196
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1197
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ t.id_board, m.id_msg |
|
1198
|
|
|
FROM {db_prefix}messages AS m |
|
1199
|
|
|
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic AND t.id_board != m.id_board) |
|
1200
|
|
|
WHERE m.id_msg > {int:id_msg_min} |
|
1201
|
|
|
AND m.id_msg <= {int:id_msg_max}', |
|
1202
|
|
|
array( |
|
1203
|
|
|
'id_msg_min' => $_REQUEST['start'], |
|
1204
|
|
|
'id_msg_max' => $_REQUEST['start'] + $increment, |
|
1205
|
|
|
) |
|
1206
|
|
|
); |
|
1207
|
|
|
$boards = array(); |
|
1208
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1209
|
|
|
$boards[$row['id_board']][] = $row['id_msg']; |
|
1210
|
|
|
$smcFunc['db_free_result']($request); |
|
1211
|
|
|
|
|
1212
|
|
|
foreach ($boards as $board_id => $messages) |
|
1213
|
|
|
$smcFunc['db_query']('', ' |
|
1214
|
|
|
UPDATE {db_prefix}messages |
|
1215
|
|
|
SET id_board = {int:id_board} |
|
1216
|
|
|
WHERE id_msg IN ({array_int:id_msg_array})', |
|
1217
|
|
|
array( |
|
1218
|
|
|
'id_msg_array' => $messages, |
|
1219
|
|
|
'id_board' => $board_id, |
|
1220
|
|
|
) |
|
1221
|
|
|
); |
|
1222
|
|
|
|
|
1223
|
|
|
$_REQUEST['start'] += $increment; |
|
1224
|
|
|
|
|
1225
|
|
|
if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 3) |
|
1226
|
|
|
{ |
|
1227
|
|
|
createToken('admin-boardrecount'); |
|
1228
|
|
|
$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-boardrecount_token_var'] . '" value="' . $context['admin-boardrecount_token'] . '">'; |
|
1229
|
|
|
|
|
1230
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=routine;activity=recount;step=6;start=' . $_REQUEST['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
1231
|
|
|
$context['continue_percent'] = round((700 + 100 * $_REQUEST['start'] / $modSettings['maxMsgID']) / $total_steps); |
|
1232
|
|
|
|
|
1233
|
|
|
return; |
|
1234
|
|
|
} |
|
1235
|
|
|
} |
|
1236
|
|
|
|
|
1237
|
|
|
$_REQUEST['start'] = 0; |
|
1238
|
|
|
} |
|
1239
|
|
|
|
|
1240
|
|
|
// Update the latest message of each board. |
|
1241
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1242
|
|
|
SELECT m.id_board, MAX(m.id_msg) AS local_last_msg |
|
1243
|
|
|
FROM {db_prefix}messages AS m |
|
1244
|
|
|
WHERE m.approved = {int:is_approved} |
|
1245
|
|
|
GROUP BY m.id_board', |
|
1246
|
|
|
array( |
|
1247
|
|
|
'is_approved' => 1, |
|
1248
|
|
|
) |
|
1249
|
|
|
); |
|
1250
|
|
|
$realBoardCounts = array(); |
|
1251
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1252
|
|
|
$realBoardCounts[$row['id_board']] = $row['local_last_msg']; |
|
1253
|
|
|
$smcFunc['db_free_result']($request); |
|
1254
|
|
|
|
|
1255
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1256
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ id_board, id_parent, id_last_msg, child_level, id_msg_updated |
|
1257
|
|
|
FROM {db_prefix}boards', |
|
1258
|
|
|
array( |
|
1259
|
|
|
) |
|
1260
|
|
|
); |
|
1261
|
|
|
$resort_me = array(); |
|
1262
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1263
|
|
|
{ |
|
1264
|
|
|
$row['local_last_msg'] = isset($realBoardCounts[$row['id_board']]) ? $realBoardCounts[$row['id_board']] : 0; |
|
1265
|
|
|
$resort_me[$row['child_level']][] = $row; |
|
1266
|
|
|
} |
|
1267
|
|
|
$smcFunc['db_free_result']($request); |
|
1268
|
|
|
|
|
1269
|
|
|
krsort($resort_me); |
|
1270
|
|
|
|
|
1271
|
|
|
$lastModifiedMsg = array(); |
|
1272
|
|
|
foreach ($resort_me as $rows) |
|
1273
|
|
|
foreach ($rows as $row) |
|
1274
|
|
|
{ |
|
1275
|
|
|
// The latest message is the latest of the current board and its children. |
|
1276
|
|
|
if (isset($lastModifiedMsg[$row['id_board']])) |
|
1277
|
|
|
$curLastModifiedMsg = max($row['local_last_msg'], $lastModifiedMsg[$row['id_board']]); |
|
1278
|
|
|
else |
|
1279
|
|
|
$curLastModifiedMsg = $row['local_last_msg']; |
|
1280
|
|
|
|
|
1281
|
|
|
// If what is and what should be the latest message differ, an update is necessary. |
|
1282
|
|
|
if ($row['local_last_msg'] != $row['id_last_msg'] || $curLastModifiedMsg != $row['id_msg_updated']) |
|
1283
|
|
|
$smcFunc['db_query']('', ' |
|
1284
|
|
|
UPDATE {db_prefix}boards |
|
1285
|
|
|
SET id_last_msg = {int:id_last_msg}, id_msg_updated = {int:id_msg_updated} |
|
1286
|
|
|
WHERE id_board = {int:id_board}', |
|
1287
|
|
|
array( |
|
1288
|
|
|
'id_last_msg' => $row['local_last_msg'], |
|
1289
|
|
|
'id_msg_updated' => $curLastModifiedMsg, |
|
1290
|
|
|
'id_board' => $row['id_board'], |
|
1291
|
|
|
) |
|
1292
|
|
|
); |
|
1293
|
|
|
|
|
1294
|
|
|
// Parent boards inherit the latest modified message of their children. |
|
1295
|
|
|
if (isset($lastModifiedMsg[$row['id_parent']])) |
|
1296
|
|
|
$lastModifiedMsg[$row['id_parent']] = max($row['local_last_msg'], $lastModifiedMsg[$row['id_parent']]); |
|
1297
|
|
|
else |
|
1298
|
|
|
$lastModifiedMsg[$row['id_parent']] = $row['local_last_msg']; |
|
1299
|
|
|
} |
|
1300
|
|
|
|
|
1301
|
|
|
// Update all the basic statistics. |
|
1302
|
|
|
updateStats('member'); |
|
1303
|
|
|
updateStats('message'); |
|
1304
|
|
|
updateStats('topic'); |
|
1305
|
|
|
|
|
1306
|
|
|
// Finally, update the latest event times. |
|
1307
|
|
|
require_once($sourcedir . '/ScheduledTasks.php'); |
|
1308
|
|
|
CalculateNextTrigger(); |
|
1309
|
|
|
|
|
1310
|
|
|
redirectexit('action=admin;area=maintain;sa=routine;done=recount'); |
|
1311
|
|
|
} |
|
1312
|
|
|
|
|
1313
|
|
|
/** |
|
1314
|
|
|
* Perform a detailed version check. A very good thing ;). |
|
1315
|
|
|
* The function parses the comment headers in all files for their version information, |
|
1316
|
|
|
* and outputs that for some javascript to check with simplemachines.org. |
|
1317
|
|
|
* It does not connect directly with simplemachines.org, but rather expects the client to. |
|
1318
|
|
|
* |
|
1319
|
|
|
* It requires the admin_forum permission. |
|
1320
|
|
|
* Uses the view_versions admin area. |
|
1321
|
|
|
* Accessed through ?action=admin;area=maintain;sa=routine;activity=version. |
|
1322
|
|
|
* @uses Admin template, view_versions sub-template. |
|
1323
|
|
|
*/ |
|
1324
|
|
|
function VersionDetail() |
|
1325
|
|
|
{ |
|
1326
|
|
|
global $forum_version, $txt, $sourcedir, $context; |
|
1327
|
|
|
|
|
1328
|
|
|
isAllowedTo('admin_forum'); |
|
1329
|
|
|
|
|
1330
|
|
|
// Call the function that'll get all the version info we need. |
|
1331
|
|
|
require_once($sourcedir . '/Subs-Admin.php'); |
|
1332
|
|
|
$versionOptions = array( |
|
1333
|
|
|
'include_ssi' => true, |
|
1334
|
|
|
'include_subscriptions' => true, |
|
1335
|
|
|
'include_tasks' => true, |
|
1336
|
|
|
'sort_results' => true, |
|
1337
|
|
|
); |
|
1338
|
|
|
$version_info = getFileVersions($versionOptions); |
|
1339
|
|
|
|
|
1340
|
|
|
// Add the new info to the template context. |
|
1341
|
|
|
$context += array( |
|
1342
|
|
|
'file_versions' => $version_info['file_versions'], |
|
1343
|
|
|
'default_template_versions' => $version_info['default_template_versions'], |
|
1344
|
|
|
'template_versions' => $version_info['template_versions'], |
|
1345
|
|
|
'default_language_versions' => $version_info['default_language_versions'], |
|
1346
|
|
|
'default_known_languages' => array_keys($version_info['default_language_versions']), |
|
1347
|
|
|
'tasks_versions' => $version_info['tasks_versions'], |
|
1348
|
|
|
); |
|
1349
|
|
|
|
|
1350
|
|
|
// Make it easier to manage for the template. |
|
1351
|
|
|
$context['forum_version'] = $forum_version; |
|
1352
|
|
|
|
|
1353
|
|
|
$context['sub_template'] = 'view_versions'; |
|
1354
|
|
|
$context['page_title'] = $txt['admin_version_check']; |
|
1355
|
|
|
} |
|
1356
|
|
|
|
|
1357
|
|
|
/** |
|
1358
|
|
|
* Re-attribute posts. |
|
1359
|
|
|
*/ |
|
1360
|
|
|
function MaintainReattributePosts() |
|
1361
|
|
|
{ |
|
1362
|
|
|
global $sourcedir, $context, $txt; |
|
1363
|
|
|
|
|
1364
|
|
|
checkSession(); |
|
1365
|
|
|
|
|
1366
|
|
|
// Find the member. |
|
1367
|
|
|
require_once($sourcedir . '/Subs-Auth.php'); |
|
1368
|
|
|
$members = findMembers($_POST['to']); |
|
1369
|
|
|
|
|
1370
|
|
|
if (empty($members)) |
|
1371
|
|
|
fatal_lang_error('reattribute_cannot_find_member'); |
|
1372
|
|
|
|
|
1373
|
|
|
$memID = array_shift($members); |
|
1374
|
|
|
$memID = $memID['id']; |
|
1375
|
|
|
|
|
1376
|
|
|
$email = $_POST['type'] == 'email' ? $_POST['from_email'] : ''; |
|
1377
|
|
|
$membername = $_POST['type'] == 'name' ? $_POST['from_name'] : ''; |
|
1378
|
|
|
|
|
1379
|
|
|
// Now call the reattribute function. |
|
1380
|
|
|
require_once($sourcedir . '/Subs-Members.php'); |
|
1381
|
|
|
reattributePosts($memID, $email, $membername, !empty($_POST['posts'])); |
|
1382
|
|
|
|
|
1383
|
|
|
$context['maintenance_finished'] = $txt['maintain_reattribute_posts']; |
|
1384
|
|
|
} |
|
1385
|
|
|
|
|
1386
|
|
|
/** |
|
1387
|
|
|
* Removing old members. Done and out! |
|
1388
|
|
|
* @todo refactor |
|
1389
|
|
|
*/ |
|
1390
|
|
|
function MaintainPurgeInactiveMembers() |
|
1391
|
|
|
{ |
|
1392
|
|
|
global $sourcedir, $context, $smcFunc, $txt; |
|
1393
|
|
|
|
|
1394
|
|
|
$_POST['maxdays'] = empty($_POST['maxdays']) ? 0 : (int) $_POST['maxdays']; |
|
1395
|
|
|
if (!empty($_POST['groups']) && $_POST['maxdays'] > 0) |
|
1396
|
|
|
{ |
|
1397
|
|
|
checkSession(); |
|
1398
|
|
|
validateToken('admin-maint'); |
|
1399
|
|
|
|
|
1400
|
|
|
$groups = array(); |
|
1401
|
|
|
foreach ($_POST['groups'] as $id => $dummy) |
|
|
|
|
|
|
1402
|
|
|
$groups[] = (int) $id; |
|
1403
|
|
|
$time_limit = (time() - ($_POST['maxdays'] * 24 * 3600)); |
|
1404
|
|
|
$where_vars = array( |
|
1405
|
|
|
'time_limit' => $time_limit, |
|
1406
|
|
|
); |
|
1407
|
|
|
if ($_POST['del_type'] == 'activated') |
|
1408
|
|
|
{ |
|
1409
|
|
|
$where = 'mem.date_registered < {int:time_limit} AND mem.is_activated = {int:is_activated}'; |
|
1410
|
|
|
$where_vars['is_activated'] = 0; |
|
1411
|
|
|
} |
|
1412
|
|
|
else |
|
1413
|
|
|
$where = 'mem.last_login < {int:time_limit} AND (mem.last_login != 0 OR mem.date_registered < {int:time_limit})'; |
|
1414
|
|
|
|
|
1415
|
|
|
// Need to get *all* groups then work out which (if any) we avoid. |
|
1416
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1417
|
|
|
SELECT id_group, group_name, min_posts |
|
1418
|
|
|
FROM {db_prefix}membergroups', |
|
1419
|
|
|
array( |
|
1420
|
|
|
) |
|
1421
|
|
|
); |
|
1422
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1423
|
|
|
{ |
|
1424
|
|
|
// Avoid this one? |
|
1425
|
|
|
if (!in_array($row['id_group'], $groups)) |
|
1426
|
|
|
{ |
|
1427
|
|
|
// Post group? |
|
1428
|
|
|
if ($row['min_posts'] != -1) |
|
1429
|
|
|
{ |
|
1430
|
|
|
$where .= ' AND mem.id_post_group != {int:id_post_group_' . $row['id_group'] . '}'; |
|
1431
|
|
|
$where_vars['id_post_group_' . $row['id_group']] = $row['id_group']; |
|
1432
|
|
|
} |
|
1433
|
|
|
else |
|
1434
|
|
|
{ |
|
1435
|
|
|
$where .= ' AND mem.id_group != {int:id_group_' . $row['id_group'] . '} AND FIND_IN_SET({int:id_group_' . $row['id_group'] . '}, mem.additional_groups) = 0'; |
|
1436
|
|
|
$where_vars['id_group_' . $row['id_group']] = $row['id_group']; |
|
1437
|
|
|
} |
|
1438
|
|
|
} |
|
1439
|
|
|
} |
|
1440
|
|
|
$smcFunc['db_free_result']($request); |
|
1441
|
|
|
|
|
1442
|
|
|
// If we have ungrouped unselected we need to avoid those guys. |
|
1443
|
|
|
if (!in_array(0, $groups)) |
|
1444
|
|
|
{ |
|
1445
|
|
|
$where .= ' AND (mem.id_group != 0 OR mem.additional_groups != {string:blank_add_groups})'; |
|
1446
|
|
|
$where_vars['blank_add_groups'] = ''; |
|
1447
|
|
|
} |
|
1448
|
|
|
|
|
1449
|
|
|
// Select all the members we're about to murder/remove... |
|
1450
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1451
|
|
|
SELECT mem.id_member, COALESCE(m.id_member, 0) AS is_mod |
|
1452
|
|
|
FROM {db_prefix}members AS mem |
|
1453
|
|
|
LEFT JOIN {db_prefix}moderators AS m ON (m.id_member = mem.id_member) |
|
1454
|
|
|
WHERE ' . $where, |
|
1455
|
|
|
$where_vars |
|
1456
|
|
|
); |
|
1457
|
|
|
$members = array(); |
|
1458
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1459
|
|
|
{ |
|
1460
|
|
|
if (!$row['is_mod'] || !in_array(3, $groups)) |
|
1461
|
|
|
$members[] = $row['id_member']; |
|
1462
|
|
|
} |
|
1463
|
|
|
$smcFunc['db_free_result']($request); |
|
1464
|
|
|
|
|
1465
|
|
|
require_once($sourcedir . '/Subs-Members.php'); |
|
1466
|
|
|
deleteMembers($members); |
|
1467
|
|
|
} |
|
1468
|
|
|
|
|
1469
|
|
|
$context['maintenance_finished'] = $txt['maintain_members']; |
|
1470
|
|
|
createToken('admin-maint'); |
|
1471
|
|
|
} |
|
1472
|
|
|
|
|
1473
|
|
|
/** |
|
1474
|
|
|
* Removing old posts doesn't take much as we really pass through. |
|
1475
|
|
|
*/ |
|
1476
|
|
|
function MaintainRemoveOldPosts() |
|
1477
|
|
|
{ |
|
1478
|
|
|
global $sourcedir; |
|
1479
|
|
|
|
|
1480
|
|
|
validateToken('admin-maint'); |
|
1481
|
|
|
|
|
1482
|
|
|
// Actually do what we're told! |
|
1483
|
|
|
require_once($sourcedir . '/RemoveTopic.php'); |
|
1484
|
|
|
RemoveOldTopics2(); |
|
1485
|
|
|
} |
|
1486
|
|
|
|
|
1487
|
|
|
/** |
|
1488
|
|
|
* Removing old drafts |
|
1489
|
|
|
*/ |
|
1490
|
|
|
function MaintainRemoveOldDrafts() |
|
1491
|
|
|
{ |
|
1492
|
|
|
global $sourcedir, $smcFunc; |
|
1493
|
|
|
|
|
1494
|
|
|
validateToken('admin-maint'); |
|
1495
|
|
|
|
|
1496
|
|
|
$drafts = array(); |
|
1497
|
|
|
|
|
1498
|
|
|
// Find all of the old drafts |
|
1499
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1500
|
|
|
SELECT id_draft |
|
1501
|
|
|
FROM {db_prefix}user_drafts |
|
1502
|
|
|
WHERE poster_time <= {int:poster_time_old}', |
|
1503
|
|
|
array( |
|
1504
|
|
|
'poster_time_old' => time() - (86400 * $_POST['draftdays']), |
|
1505
|
|
|
) |
|
1506
|
|
|
); |
|
1507
|
|
|
|
|
1508
|
|
|
while ($row = $smcFunc['db_fetch_row']($request)) |
|
1509
|
|
|
$drafts[] = (int) $row[0]; |
|
1510
|
|
|
$smcFunc['db_free_result']($request); |
|
1511
|
|
|
|
|
1512
|
|
|
// If we have old drafts, remove them |
|
1513
|
|
|
if (count($drafts) > 0) |
|
1514
|
|
|
{ |
|
1515
|
|
|
require_once($sourcedir . '/Drafts.php'); |
|
1516
|
|
|
DeleteDraft($drafts, false); |
|
|
|
|
|
|
1517
|
|
|
} |
|
1518
|
|
|
} |
|
1519
|
|
|
|
|
1520
|
|
|
/** |
|
1521
|
|
|
* Moves topics from one board to another. |
|
1522
|
|
|
* |
|
1523
|
|
|
* @uses not_done template to pause the process. |
|
1524
|
|
|
*/ |
|
1525
|
|
|
function MaintainMassMoveTopics() |
|
1526
|
|
|
{ |
|
1527
|
|
|
global $smcFunc, $sourcedir, $context, $txt; |
|
1528
|
|
|
|
|
1529
|
|
|
// Only admins. |
|
1530
|
|
|
isAllowedTo('admin_forum'); |
|
1531
|
|
|
|
|
1532
|
|
|
checkSession('request'); |
|
1533
|
|
|
validateToken('admin-maint'); |
|
1534
|
|
|
|
|
1535
|
|
|
// Set up to the context. |
|
1536
|
|
|
$context['page_title'] = $txt['not_done_title']; |
|
1537
|
|
|
$context['continue_countdown'] = 3; |
|
1538
|
|
|
$context['continue_post_data'] = ''; |
|
1539
|
|
|
$context['continue_get_data'] = ''; |
|
1540
|
|
|
$context['sub_template'] = 'not_done'; |
|
1541
|
|
|
$context['start'] = empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start']; |
|
1542
|
|
|
$context['start_time'] = time(); |
|
1543
|
|
|
|
|
1544
|
|
|
// First time we do this? |
|
1545
|
|
|
$id_board_from = isset($_REQUEST['id_board_from']) ? (int) $_REQUEST['id_board_from'] : 0; |
|
1546
|
|
|
$id_board_to = isset($_REQUEST['id_board_to']) ? (int) $_REQUEST['id_board_to'] : 0; |
|
1547
|
|
|
$max_days = isset($_REQUEST['maxdays']) ? (int) $_REQUEST['maxdays'] : 0; |
|
1548
|
|
|
$locked = isset($_POST['move_type_locked']) || isset($_GET['locked']); |
|
1549
|
|
|
$sticky = isset($_POST['move_type_sticky']) || isset($_GET['sticky']); |
|
1550
|
|
|
|
|
1551
|
|
|
// No boards then this is your stop. |
|
1552
|
|
|
if (empty($id_board_from) || empty($id_board_to)) |
|
1553
|
|
|
return; |
|
1554
|
|
|
|
|
1555
|
|
|
// The big WHERE clause |
|
1556
|
|
|
$conditions = 'WHERE t.id_board = {int:id_board_from} |
|
1557
|
|
|
AND m.icon != {string:moved}'; |
|
1558
|
|
|
|
|
1559
|
|
|
// DB parameters |
|
1560
|
|
|
$params = array( |
|
1561
|
|
|
'id_board_from' => $id_board_from, |
|
1562
|
|
|
'moved' => 'moved', |
|
1563
|
|
|
); |
|
1564
|
|
|
|
|
1565
|
|
|
// Only moving topics not posted in for x days? |
|
1566
|
|
|
if (!empty($max_days)) |
|
1567
|
|
|
{ |
|
1568
|
|
|
$conditions .= ' |
|
1569
|
|
|
AND m.poster_time < {int:poster_time}'; |
|
1570
|
|
|
$params['poster_time'] = time() - 3600 * 24 * $max_days; |
|
1571
|
|
|
} |
|
1572
|
|
|
|
|
1573
|
|
|
// Moving locked topics? |
|
1574
|
|
|
if ($locked) |
|
1575
|
|
|
{ |
|
1576
|
|
|
$conditions .= ' |
|
1577
|
|
|
AND t.locked = {int:locked}'; |
|
1578
|
|
|
$params['locked'] = 1; |
|
1579
|
|
|
} |
|
1580
|
|
|
|
|
1581
|
|
|
// What about sticky topics? |
|
1582
|
|
|
if ($sticky) |
|
1583
|
|
|
{ |
|
1584
|
|
|
$conditions .= ' |
|
1585
|
|
|
AND t.is_sticky = {int:sticky}'; |
|
1586
|
|
|
$params['sticky'] = 1; |
|
1587
|
|
|
} |
|
1588
|
|
|
|
|
1589
|
|
|
// How many topics are we converting? |
|
1590
|
|
|
if (!isset($_REQUEST['totaltopics'])) |
|
1591
|
|
|
{ |
|
1592
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1593
|
|
|
SELECT COUNT(*) |
|
1594
|
|
|
FROM {db_prefix}topics AS t |
|
1595
|
|
|
INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_last_msg)' . |
|
1596
|
|
|
$conditions, |
|
1597
|
|
|
$params |
|
1598
|
|
|
); |
|
1599
|
|
|
list ($total_topics) = $smcFunc['db_fetch_row']($request); |
|
1600
|
|
|
$smcFunc['db_free_result']($request); |
|
1601
|
|
|
} |
|
1602
|
|
|
else |
|
1603
|
|
|
$total_topics = (int) $_REQUEST['totaltopics']; |
|
1604
|
|
|
|
|
1605
|
|
|
// Seems like we need this here. |
|
1606
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=topics;activity=massmove;id_board_from=' . $id_board_from . ';id_board_to=' . $id_board_to . ';totaltopics=' . $total_topics . ';max_days=' . $max_days; |
|
1607
|
|
|
|
|
1608
|
|
|
if ($locked) |
|
1609
|
|
|
$context['continue_get_data'] .= ';locked'; |
|
1610
|
|
|
|
|
1611
|
|
|
if ($sticky) |
|
1612
|
|
|
$context['continue_get_data'] .= ';sticky'; |
|
1613
|
|
|
|
|
1614
|
|
|
$context['continue_get_data'] .= ';start=' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
1615
|
|
|
|
|
1616
|
|
|
// We have topics to move so start the process. |
|
1617
|
|
|
if (!empty($total_topics)) |
|
1618
|
|
|
{ |
|
1619
|
|
|
while ($context['start'] <= $total_topics) |
|
1620
|
|
|
{ |
|
1621
|
|
|
// Lets get the topics. |
|
1622
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1623
|
|
|
SELECT t.id_topic |
|
1624
|
|
|
FROM {db_prefix}topics AS t |
|
1625
|
|
|
INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_last_msg) |
|
1626
|
|
|
' . $conditions . ' |
|
1627
|
|
|
LIMIT 10', |
|
1628
|
|
|
$params |
|
1629
|
|
|
); |
|
1630
|
|
|
|
|
1631
|
|
|
// Get the ids. |
|
1632
|
|
|
$topics = array(); |
|
1633
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1634
|
|
|
$topics[] = $row['id_topic']; |
|
1635
|
|
|
|
|
1636
|
|
|
// Just return if we don't have any topics left to move. |
|
1637
|
|
|
if (empty($topics)) |
|
1638
|
|
|
{ |
|
1639
|
|
|
cache_put_data('board-' . $id_board_from, null, 120); |
|
1640
|
|
|
cache_put_data('board-' . $id_board_to, null, 120); |
|
1641
|
|
|
redirectexit('action=admin;area=maintain;sa=topics;done=massmove'); |
|
1642
|
|
|
} |
|
1643
|
|
|
|
|
1644
|
|
|
// Lets move them. |
|
1645
|
|
|
require_once($sourcedir . '/MoveTopic.php'); |
|
1646
|
|
|
moveTopics($topics, $id_board_to); |
|
1647
|
|
|
|
|
1648
|
|
|
// We've done at least ten more topics. |
|
1649
|
|
|
$context['start'] += 10; |
|
1650
|
|
|
|
|
1651
|
|
|
// Lets wait a while. |
|
1652
|
|
|
if (time() - $context['start_time'] > 3) |
|
1653
|
|
|
{ |
|
1654
|
|
|
// What's the percent? |
|
1655
|
|
|
$context['continue_percent'] = round(100 * ($context['start'] / $total_topics), 1); |
|
1656
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=topics;activity=massmove;id_board_from=' . $id_board_from . ';id_board_to=' . $id_board_to . ';totaltopics=' . $total_topics . ';start=' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
1657
|
|
|
|
|
1658
|
|
|
// Let the template system do it's thang. |
|
1659
|
|
|
return; |
|
1660
|
|
|
} |
|
1661
|
|
|
} |
|
1662
|
|
|
} |
|
1663
|
|
|
|
|
1664
|
|
|
// Don't confuse admins by having an out of date cache. |
|
1665
|
|
|
cache_put_data('board-' . $id_board_from, null, 120); |
|
1666
|
|
|
cache_put_data('board-' . $id_board_to, null, 120); |
|
1667
|
|
|
|
|
1668
|
|
|
redirectexit('action=admin;area=maintain;sa=topics;done=massmove'); |
|
1669
|
|
|
} |
|
1670
|
|
|
|
|
1671
|
|
|
/** |
|
1672
|
|
|
* Recalculate all members post counts |
|
1673
|
|
|
* it requires the admin_forum permission. |
|
1674
|
|
|
* |
|
1675
|
|
|
* - recounts all posts for members found in the message table |
|
1676
|
|
|
* - updates the members post count record in the members table |
|
1677
|
|
|
* - honors the boards post count flag |
|
1678
|
|
|
* - does not count posts in the recycle bin |
|
1679
|
|
|
* - zeros post counts for all members with no posts in the message table |
|
1680
|
|
|
* - runs as a delayed loop to avoid server overload |
|
1681
|
|
|
* - uses the not_done template in Admin.template |
|
1682
|
|
|
* |
|
1683
|
|
|
* The function redirects back to action=admin;area=maintain;sa=members when complete. |
|
1684
|
|
|
* It is accessed via ?action=admin;area=maintain;sa=members;activity=recountposts |
|
1685
|
|
|
*/ |
|
1686
|
|
|
function MaintainRecountPosts() |
|
1687
|
|
|
{ |
|
1688
|
|
|
global $txt, $context, $modSettings, $smcFunc; |
|
1689
|
|
|
|
|
1690
|
|
|
// You have to be allowed in here |
|
1691
|
|
|
isAllowedTo('admin_forum'); |
|
1692
|
|
|
checkSession('request'); |
|
1693
|
|
|
|
|
1694
|
|
|
// Set up to the context. |
|
1695
|
|
|
$context['page_title'] = $txt['not_done_title']; |
|
1696
|
|
|
$context['continue_countdown'] = 3; |
|
1697
|
|
|
$context['continue_get_data'] = ''; |
|
1698
|
|
|
$context['sub_template'] = 'not_done'; |
|
1699
|
|
|
|
|
1700
|
|
|
// init |
|
1701
|
|
|
$increment = 200; |
|
1702
|
|
|
$_REQUEST['start'] = !isset($_REQUEST['start']) ? 0 : (int) $_REQUEST['start']; |
|
1703
|
|
|
|
|
1704
|
|
|
// Ask for some extra time, on big boards this may take a bit |
|
1705
|
|
|
@set_time_limit(600); |
|
|
|
|
|
|
1706
|
|
|
|
|
1707
|
|
|
// Only run this query if we don't have the total number of members that have posted |
|
1708
|
|
|
if (!isset($_SESSION['total_members'])) |
|
1709
|
|
|
{ |
|
1710
|
|
|
validateToken('admin-maint'); |
|
1711
|
|
|
|
|
1712
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1713
|
|
|
SELECT COUNT(DISTINCT m.id_member) |
|
1714
|
|
|
FROM {db_prefix}messages AS m |
|
1715
|
|
|
JOIN {db_prefix}boards AS b on m.id_board = b.id_board |
|
1716
|
|
|
WHERE m.id_member != 0 |
|
1717
|
|
|
AND b.count_posts = 0', |
|
1718
|
|
|
array( |
|
1719
|
|
|
) |
|
1720
|
|
|
); |
|
1721
|
|
|
|
|
1722
|
|
|
// save it so we don't do this again for this task |
|
1723
|
|
|
list ($_SESSION['total_members']) = $smcFunc['db_fetch_row']($request); |
|
1724
|
|
|
$smcFunc['db_free_result']($request); |
|
1725
|
|
|
} |
|
1726
|
|
|
else |
|
1727
|
|
|
validateToken('admin-recountposts'); |
|
1728
|
|
|
|
|
1729
|
|
|
// Lets get a group of members and determine their post count (from the boards that have post count enabled of course). |
|
1730
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1731
|
|
|
SELECT /*!40001 SQL_NO_CACHE */ m.id_member, COUNT(m.id_member) AS posts |
|
1732
|
|
|
FROM ({db_prefix}messages AS m, {db_prefix}boards AS b) |
|
1733
|
|
|
WHERE m.id_member != {int:zero} |
|
1734
|
|
|
AND b.count_posts = {int:zero} |
|
1735
|
|
|
AND m.id_board = b.id_board ' . (!empty($modSettings['recycle_enable']) ? ' |
|
1736
|
|
|
AND b.id_board != {int:recycle}' : '') . ' |
|
1737
|
|
|
GROUP BY m.id_member |
|
1738
|
|
|
LIMIT {int:start}, {int:number}', |
|
1739
|
|
|
array( |
|
1740
|
|
|
'start' => $_REQUEST['start'], |
|
1741
|
|
|
'number' => $increment, |
|
1742
|
|
|
'recycle' => $modSettings['recycle_board'], |
|
1743
|
|
|
'zero' => 0, |
|
1744
|
|
|
) |
|
1745
|
|
|
); |
|
1746
|
|
|
$total_rows = $smcFunc['db_num_rows']($request); |
|
1747
|
|
|
|
|
1748
|
|
|
// Update the post count for this group |
|
1749
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1750
|
|
|
{ |
|
1751
|
|
|
$smcFunc['db_query']('', ' |
|
1752
|
|
|
UPDATE {db_prefix}members |
|
1753
|
|
|
SET posts = {int:posts} |
|
1754
|
|
|
WHERE id_member = {int:row}', |
|
1755
|
|
|
array( |
|
1756
|
|
|
'row' => $row['id_member'], |
|
1757
|
|
|
'posts' => $row['posts'], |
|
1758
|
|
|
) |
|
1759
|
|
|
); |
|
1760
|
|
|
} |
|
1761
|
|
|
$smcFunc['db_free_result']($request); |
|
1762
|
|
|
|
|
1763
|
|
|
// Continue? |
|
1764
|
|
|
if ($total_rows == $increment) |
|
1765
|
|
|
{ |
|
1766
|
|
|
$_REQUEST['start'] += $increment; |
|
1767
|
|
|
$context['continue_get_data'] = '?action=admin;area=maintain;sa=members;activity=recountposts;start=' . $_REQUEST['start'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
1768
|
|
|
$context['continue_percent'] = round(100 * $_REQUEST['start'] / $_SESSION['total_members']); |
|
1769
|
|
|
|
|
1770
|
|
|
createToken('admin-recountposts'); |
|
1771
|
|
|
$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-recountposts_token_var'] . '" value="' . $context['admin-recountposts_token'] . '">'; |
|
1772
|
|
|
|
|
1773
|
|
|
if (function_exists('apache_reset_timeout')) |
|
1774
|
|
|
apache_reset_timeout(); |
|
1775
|
|
|
return; |
|
1776
|
|
|
} |
|
1777
|
|
|
|
|
1778
|
|
|
// final steps ... made more difficult since we don't yet support sub-selects on joins |
|
1779
|
|
|
// place all members who have posts in the message table in a temp table |
|
1780
|
|
|
$createTemporary = $smcFunc['db_query']('', ' |
|
1781
|
|
|
CREATE TEMPORARY TABLE {db_prefix}tmp_maint_recountposts ( |
|
1782
|
|
|
id_member mediumint(8) unsigned NOT NULL default {string:string_zero}, |
|
1783
|
|
|
PRIMARY KEY (id_member) |
|
1784
|
|
|
) |
|
1785
|
|
|
SELECT m.id_member |
|
1786
|
|
|
FROM ({db_prefix}messages AS m,{db_prefix}boards AS b) |
|
1787
|
|
|
WHERE m.id_member != {int:zero} |
|
1788
|
|
|
AND b.count_posts = {int:zero} |
|
1789
|
|
|
AND m.id_board = b.id_board ' . (!empty($modSettings['recycle_enable']) ? ' |
|
1790
|
|
|
AND b.id_board != {int:recycle}' : '') . ' |
|
1791
|
|
|
GROUP BY m.id_member', |
|
1792
|
|
|
array( |
|
1793
|
|
|
'zero' => 0, |
|
1794
|
|
|
'string_zero' => '0', |
|
1795
|
|
|
'db_error_skip' => true, |
|
1796
|
|
|
'recycle' => !empty($modSettings['recycle_board']) ? $modSettings['recycle_board'] : 0, |
|
1797
|
|
|
) |
|
1798
|
|
|
) !== false; |
|
1799
|
|
|
|
|
1800
|
|
View Code Duplication |
if ($createTemporary) |
|
|
|
|
|
|
1801
|
|
|
{ |
|
1802
|
|
|
// outer join the members table on the temporary table finding the members that have a post count but no posts in the message table |
|
1803
|
|
|
$request = $smcFunc['db_query']('', ' |
|
1804
|
|
|
SELECT mem.id_member, mem.posts |
|
1805
|
|
|
FROM {db_prefix}members AS mem |
|
1806
|
|
|
LEFT OUTER JOIN {db_prefix}tmp_maint_recountposts AS res |
|
1807
|
|
|
ON res.id_member = mem.id_member |
|
1808
|
|
|
WHERE res.id_member IS null |
|
1809
|
|
|
AND mem.posts != {int:zero}', |
|
1810
|
|
|
array( |
|
1811
|
|
|
'zero' => 0, |
|
1812
|
|
|
) |
|
1813
|
|
|
); |
|
1814
|
|
|
|
|
1815
|
|
|
// set the post count to zero for any delinquents we may have found |
|
1816
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
1817
|
|
|
{ |
|
1818
|
|
|
$smcFunc['db_query']('', ' |
|
1819
|
|
|
UPDATE {db_prefix}members |
|
1820
|
|
|
SET posts = {int:zero} |
|
1821
|
|
|
WHERE id_member = {int:row}', |
|
1822
|
|
|
array( |
|
1823
|
|
|
'row' => $row['id_member'], |
|
1824
|
|
|
'zero' => 0, |
|
1825
|
|
|
) |
|
1826
|
|
|
); |
|
1827
|
|
|
} |
|
1828
|
|
|
$smcFunc['db_free_result']($request); |
|
1829
|
|
|
} |
|
1830
|
|
|
|
|
1831
|
|
|
// all done |
|
1832
|
|
|
unset($_SESSION['total_members']); |
|
1833
|
|
|
$context['maintenance_finished'] = $txt['maintain_recountposts']; |
|
1834
|
|
|
redirectexit('action=admin;area=maintain;sa=members;done=recountposts'); |
|
1835
|
|
|
} |
|
1836
|
|
|
|
|
1837
|
|
|
/** |
|
1838
|
|
|
* Generates a list of integration hooks for display |
|
1839
|
|
|
* Accessed through ?action=admin;area=maintain;sa=hooks; |
|
1840
|
|
|
* Allows for removal or disabling of selected hooks |
|
1841
|
|
|
*/ |
|
1842
|
|
|
function list_integration_hooks() |
|
1843
|
|
|
{ |
|
1844
|
|
|
global $sourcedir, $scripturl, $context, $txt; |
|
1845
|
|
|
|
|
1846
|
|
|
$context['filter_url'] = ''; |
|
1847
|
|
|
$context['current_filter'] = ''; |
|
1848
|
|
|
$currentHooks = get_integration_hooks(); |
|
1849
|
|
|
if (isset($_GET['filter']) && in_array($_GET['filter'], array_keys($currentHooks))) |
|
1850
|
|
|
{ |
|
1851
|
|
|
$context['filter_url'] = ';filter=' . $_GET['filter']; |
|
1852
|
|
|
$context['current_filter'] = $_GET['filter']; |
|
1853
|
|
|
} |
|
1854
|
|
|
|
|
1855
|
|
|
if (!empty($_REQUEST['do']) && isset($_REQUEST['hook']) && isset($_REQUEST['function'])) |
|
1856
|
|
|
{ |
|
1857
|
|
|
checkSession('request'); |
|
1858
|
|
|
validateToken('admin-hook', 'request'); |
|
1859
|
|
|
|
|
1860
|
|
|
if ($_REQUEST['do'] == 'remove') |
|
1861
|
|
|
remove_integration_function($_REQUEST['hook'], urldecode($_REQUEST['function'])); |
|
1862
|
|
|
|
|
1863
|
|
|
else |
|
1864
|
|
|
{ |
|
1865
|
|
|
$function_remove = urldecode($_REQUEST['function']) . (($_REQUEST['do'] == 'disable') ? '' : '!'); |
|
1866
|
|
|
$function_add = urldecode($_REQUEST['function']) . (($_REQUEST['do'] == 'disable') ? '!' : ''); |
|
1867
|
|
|
|
|
1868
|
|
|
remove_integration_function($_REQUEST['hook'], $function_remove); |
|
1869
|
|
|
add_integration_function($_REQUEST['hook'], $function_add); |
|
1870
|
|
|
|
|
1871
|
|
|
redirectexit('action=admin;area=maintain;sa=hooks' . $context['filter_url']); |
|
1872
|
|
|
} |
|
1873
|
|
|
} |
|
1874
|
|
|
|
|
1875
|
|
|
createToken('admin-hook', 'request'); |
|
1876
|
|
|
|
|
1877
|
|
|
$list_options = array( |
|
1878
|
|
|
'id' => 'list_integration_hooks', |
|
1879
|
|
|
'title' => $txt['hooks_title_list'], |
|
1880
|
|
|
'items_per_page' => 20, |
|
1881
|
|
|
'base_href' => $scripturl . '?action=admin;area=maintain;sa=hooks' . $context['filter_url'] . ';' . $context['session_var'] . '=' . $context['session_id'], |
|
1882
|
|
|
'default_sort_col' => 'hook_name', |
|
1883
|
|
|
'get_items' => array( |
|
1884
|
|
|
'function' => 'get_integration_hooks_data', |
|
1885
|
|
|
), |
|
1886
|
|
|
'get_count' => array( |
|
1887
|
|
|
'function' => 'get_integration_hooks_count', |
|
1888
|
|
|
), |
|
1889
|
|
|
'no_items_label' => $txt['hooks_no_hooks'], |
|
1890
|
|
|
'columns' => array( |
|
1891
|
|
|
'hook_name' => array( |
|
1892
|
|
|
'header' => array( |
|
1893
|
|
|
'value' => $txt['hooks_field_hook_name'], |
|
1894
|
|
|
), |
|
1895
|
|
|
'data' => array( |
|
1896
|
|
|
'db' => 'hook_name', |
|
1897
|
|
|
), |
|
1898
|
|
|
'sort' => array( |
|
1899
|
|
|
'default' => 'hook_name', |
|
1900
|
|
|
'reverse' => 'hook_name DESC', |
|
1901
|
|
|
), |
|
1902
|
|
|
), |
|
1903
|
|
|
'function_name' => array( |
|
1904
|
|
|
'header' => array( |
|
1905
|
|
|
'value' => $txt['hooks_field_function_name'], |
|
1906
|
|
|
), |
|
1907
|
|
|
'data' => array( |
|
1908
|
|
|
'function' => function ($data) use ($txt) |
|
1909
|
|
|
{ |
|
1910
|
|
|
// Show a nice icon to indicate this is an instance. |
|
1911
|
|
|
$instance = (!empty($data['instance']) ? '<span class="generic_icons news" title="'. $txt['hooks_field_function_method'] .'"></span> ' : ''); |
|
1912
|
|
|
|
|
1913
|
|
|
if (!empty($data['included_file'])) |
|
1914
|
|
|
return $instance . $txt['hooks_field_function'] . ': ' . $data['real_function'] . '<br>' . $txt['hooks_field_included_file'] . ': ' . $data['included_file']; |
|
1915
|
|
|
|
|
1916
|
|
|
else |
|
1917
|
|
|
return $instance . $data['real_function']; |
|
1918
|
|
|
}, |
|
1919
|
|
|
), |
|
1920
|
|
|
'sort' => array( |
|
1921
|
|
|
'default' => 'function_name', |
|
1922
|
|
|
'reverse' => 'function_name DESC', |
|
1923
|
|
|
), |
|
1924
|
|
|
), |
|
1925
|
|
|
'file_name' => array( |
|
1926
|
|
|
'header' => array( |
|
1927
|
|
|
'value' => $txt['hooks_field_file_name'], |
|
1928
|
|
|
), |
|
1929
|
|
|
'data' => array( |
|
1930
|
|
|
'db' => 'file_name', |
|
1931
|
|
|
), |
|
1932
|
|
|
'sort' => array( |
|
1933
|
|
|
'default' => 'file_name', |
|
1934
|
|
|
'reverse' => 'file_name DESC', |
|
1935
|
|
|
), |
|
1936
|
|
|
), |
|
1937
|
|
|
'status' => array( |
|
1938
|
|
|
'header' => array( |
|
1939
|
|
|
'value' => $txt['hooks_field_hook_exists'], |
|
1940
|
|
|
'style' => 'width:3%;', |
|
1941
|
|
|
), |
|
1942
|
|
|
'data' => array( |
|
1943
|
|
|
'function' => function ($data) use ($txt, $scripturl, $context) |
|
1944
|
|
|
{ |
|
1945
|
|
|
$change_status = array('before' => '', 'after' => ''); |
|
1946
|
|
|
|
|
1947
|
|
|
$change_status['before'] = '<a href="' . $scripturl . '?action=admin;area=maintain;sa=hooks;do=' . ($data['enabled'] ? 'disable' : 'enable') . ';hook=' . $data['hook_name'] . ';function=' . urlencode($data['function_name']) . $context['filter_url'] . ';' . $context['admin-hook_token_var'] . '=' . $context['admin-hook_token'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" data-confirm="' . $txt['quickmod_confirm'] . '" class="you_sure">'; |
|
1948
|
|
|
$change_status['after'] = '</a>'; |
|
1949
|
|
|
|
|
1950
|
|
|
return $change_status['before'] . '<span class="generic_icons post_moderation_' . $data['status'] . '" title="' . $data['img_text'] . '"></span>'; |
|
1951
|
|
|
}, |
|
1952
|
|
|
'class' => 'centertext', |
|
1953
|
|
|
), |
|
1954
|
|
|
'sort' => array( |
|
1955
|
|
|
'default' => 'status', |
|
1956
|
|
|
'reverse' => 'status DESC', |
|
1957
|
|
|
), |
|
1958
|
|
|
), |
|
1959
|
|
|
), |
|
1960
|
|
|
'additional_rows' => array( |
|
1961
|
|
|
array( |
|
1962
|
|
|
'position' => 'after_title', |
|
1963
|
|
|
'value' => $txt['hooks_disable_instructions'] . '<br> |
|
1964
|
|
|
' . $txt['hooks_disable_legend'] . ': |
|
1965
|
|
|
<ul style="list-style: none;"> |
|
1966
|
|
|
<li><span class="generic_icons post_moderation_allow"></span> ' . $txt['hooks_disable_legend_exists'] . '</li> |
|
1967
|
|
|
<li><span class="generic_icons post_moderation_moderate"></span> ' . $txt['hooks_disable_legend_disabled'] . '</li> |
|
1968
|
|
|
<li><span class="generic_icons post_moderation_deny"></span> ' . $txt['hooks_disable_legend_missing'] . '</li> |
|
1969
|
|
|
</ul>' |
|
1970
|
|
|
), |
|
1971
|
|
|
), |
|
1972
|
|
|
); |
|
1973
|
|
|
|
|
1974
|
|
|
$list_options['columns']['remove'] = array( |
|
1975
|
|
|
'header' => array( |
|
1976
|
|
|
'value' => $txt['hooks_button_remove'], |
|
1977
|
|
|
'style' => 'width:3%', |
|
1978
|
|
|
), |
|
1979
|
|
|
'data' => array( |
|
1980
|
|
|
'function' => function ($data) use ($txt, $scripturl, $context) |
|
1981
|
|
|
{ |
|
1982
|
|
|
if (!$data['hook_exists']) |
|
1983
|
|
|
return ' |
|
1984
|
|
|
<a href="' . $scripturl . '?action=admin;area=maintain;sa=hooks;do=remove;hook=' . $data['hook_name'] . ';function=' . urlencode($data['function_name']) . $context['filter_url'] . ';' . $context['admin-hook_token_var'] . '=' . $context['admin-hook_token'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" data-confirm="' . $txt['quickmod_confirm'] . '" class="you_sure"> |
|
1985
|
|
|
<span class="generic_icons delete" title="' . $txt['hooks_button_remove'] . '"></span> |
|
1986
|
|
|
</a>'; |
|
1987
|
|
|
}, |
|
1988
|
|
|
'class' => 'centertext', |
|
1989
|
|
|
), |
|
1990
|
|
|
); |
|
1991
|
|
|
$list_options['form'] = array( |
|
1992
|
|
|
'href' => $scripturl . '?action=admin;area=maintain;sa=hooks' . $context['filter_url'] . ';' . $context['session_var'] . '=' . $context['session_id'], |
|
1993
|
|
|
'name' => 'list_integration_hooks', |
|
1994
|
|
|
); |
|
1995
|
|
|
|
|
1996
|
|
|
|
|
1997
|
|
|
require_once($sourcedir . '/Subs-List.php'); |
|
1998
|
|
|
createList($list_options); |
|
1999
|
|
|
|
|
2000
|
|
|
$context['page_title'] = $txt['hooks_title_list']; |
|
2001
|
|
|
$context['sub_template'] = 'show_list'; |
|
2002
|
|
|
$context['default_list'] = 'list_integration_hooks'; |
|
2003
|
|
|
} |
|
2004
|
|
|
|
|
2005
|
|
|
/** |
|
2006
|
|
|
* Gets all of the files in a directory and its children directories |
|
2007
|
|
|
* |
|
2008
|
|
|
* @param string $dir_path The path to the directory |
|
2009
|
|
|
* @return array An array containing information about the files found in the specified directory and its children |
|
2010
|
|
|
*/ |
|
2011
|
|
|
function get_files_recursive($dir_path) |
|
2012
|
|
|
{ |
|
2013
|
|
|
$files = array(); |
|
2014
|
|
|
|
|
2015
|
|
|
if ($dh = opendir($dir_path)) |
|
2016
|
|
|
{ |
|
2017
|
|
|
while (($file = readdir($dh)) !== false) |
|
2018
|
|
|
{ |
|
2019
|
|
|
if ($file != '.' && $file != '..') |
|
2020
|
|
|
{ |
|
2021
|
|
|
if (is_dir($dir_path . '/' . $file)) |
|
2022
|
|
|
$files = array_merge($files, get_files_recursive($dir_path . '/' . $file)); |
|
2023
|
|
|
else |
|
2024
|
|
|
$files[] = array('dir' => $dir_path, 'name' => $file); |
|
2025
|
|
|
} |
|
2026
|
|
|
} |
|
2027
|
|
|
} |
|
2028
|
|
|
closedir($dh); |
|
2029
|
|
|
|
|
2030
|
|
|
return $files; |
|
2031
|
|
|
} |
|
2032
|
|
|
|
|
2033
|
|
|
/** |
|
2034
|
|
|
* Callback function for the integration hooks list (list_integration_hooks) |
|
2035
|
|
|
* Gets all of the hooks in the system and their status |
|
2036
|
|
|
* |
|
2037
|
|
|
* @param int $start The item to start with (for pagination purposes) |
|
2038
|
|
|
* @param int $per_page How many items to display on each page |
|
2039
|
|
|
* @param string $sort A string indicating how to sort things |
|
2040
|
|
|
* @return array An array of information about the integration hooks |
|
2041
|
|
|
*/ |
|
2042
|
|
|
function get_integration_hooks_data($start, $per_page, $sort) |
|
2043
|
|
|
{ |
|
2044
|
|
|
global $boarddir, $sourcedir, $settings, $txt, $context, $scripturl; |
|
2045
|
|
|
|
|
2046
|
|
|
$hooks = $temp_hooks = get_integration_hooks(); |
|
2047
|
|
|
$hooks_data = $temp_data = $hook_status = array(); |
|
2048
|
|
|
|
|
2049
|
|
|
$files = get_files_recursive($sourcedir); |
|
2050
|
|
|
if (!empty($files)) |
|
2051
|
|
|
{ |
|
2052
|
|
|
foreach ($files as $file) |
|
2053
|
|
|
{ |
|
2054
|
|
|
if (is_file($file['dir'] . '/' . $file['name']) && substr($file['name'], -4) === '.php') |
|
2055
|
|
|
{ |
|
2056
|
|
|
$fp = fopen($file['dir'] . '/' . $file['name'], 'rb'); |
|
2057
|
|
|
$fc = fread($fp, filesize($file['dir'] . '/' . $file['name'])); |
|
2058
|
|
|
fclose($fp); |
|
2059
|
|
|
|
|
2060
|
|
|
foreach ($temp_hooks as $hook => $allFunctions) |
|
2061
|
|
|
{ |
|
2062
|
|
|
foreach ($allFunctions as $rawFunc) |
|
2063
|
|
|
{ |
|
2064
|
|
|
// Get the hook info. |
|
2065
|
|
|
$hookParsedData = get_hook_info_from_raw($rawFunc); |
|
2066
|
|
|
|
|
2067
|
|
|
if (substr($hook, -8) === '_include') |
|
2068
|
|
|
{ |
|
2069
|
|
|
$hook_status[$hook][$hookParsedData['pureFunc']]['exists'] = file_exists(strtr(trim($rawFunc), array('$boarddir' => $boarddir, '$sourcedir' => $sourcedir, '$themedir' => $settings['theme_dir']))); |
|
2070
|
|
|
// I need to know if there is at least one function called in this file. |
|
2071
|
|
|
$temp_data['include'][$hookParsedData['pureFunc']] = array('hook' => $hook, 'function' => $hookParsedData['pureFunc']); |
|
2072
|
|
|
unset($temp_hooks[$hook][$rawFunc]); |
|
2073
|
|
|
} |
|
2074
|
|
|
elseif (strpos(str_replace(' (', '(', $fc), 'function ' . trim($hookParsedData['pureFunc']) . '(') !== false) |
|
2075
|
|
|
{ |
|
2076
|
|
|
$hook_status[$hook][$hookParsedData['pureFunc']] = $hookParsedData; |
|
2077
|
|
|
$hook_status[$hook][$hookParsedData['pureFunc']]['exists'] = true; |
|
2078
|
|
|
$hook_status[$hook][$hookParsedData['pureFunc']]['in_file'] = (!empty($file['name']) ? $file['name'] : (!empty($hookParsedData['hookFile']) ? $hookParsedData['hookFile'] : '')); |
|
2079
|
|
|
|
|
2080
|
|
|
// Does the hook has its own file? |
|
2081
|
|
|
if (!empty($hookParsedData['hookFile'])) |
|
2082
|
|
|
$temp_data['include'][$hookParsedData['pureFunc']] = array('hook' => $hook, 'function' => $hookParsedData['pureFunc']); |
|
2083
|
|
|
|
|
2084
|
|
|
// I want to remember all the functions called within this file (to check later if they are enabled or disabled and decide if the integrare_*_include of that file can be disabled too) |
|
2085
|
|
|
$temp_data['function'][$file['name']][$hookParsedData['pureFunc']] = $hookParsedData['enabled']; |
|
2086
|
|
|
unset($temp_hooks[$hook][$rawFunc]); |
|
2087
|
|
|
} |
|
2088
|
|
|
} |
|
2089
|
|
|
} |
|
2090
|
|
|
} |
|
2091
|
|
|
} |
|
2092
|
|
|
} |
|
2093
|
|
|
|
|
2094
|
|
|
$sort_types = array( |
|
2095
|
|
|
'hook_name' => array('hook', SORT_ASC), |
|
2096
|
|
|
'hook_name DESC' => array('hook', SORT_DESC), |
|
2097
|
|
|
'function_name' => array('function', SORT_ASC), |
|
2098
|
|
|
'function_name DESC' => array('function', SORT_DESC), |
|
2099
|
|
|
'file_name' => array('file_name', SORT_ASC), |
|
2100
|
|
|
'file_name DESC' => array('file_name', SORT_DESC), |
|
2101
|
|
|
'status' => array('status', SORT_ASC), |
|
2102
|
|
|
'status DESC' => array('status', SORT_DESC), |
|
2103
|
|
|
); |
|
2104
|
|
|
|
|
2105
|
|
|
$sort_options = $sort_types[$sort]; |
|
2106
|
|
|
$sort = array(); |
|
2107
|
|
|
$hooks_filters = array(); |
|
2108
|
|
|
|
|
2109
|
|
|
foreach ($hooks as $hook => $functions) |
|
2110
|
|
|
$hooks_filters[] = '<option' . ($context['current_filter'] == $hook ? ' selected ' : '') . ' value="' . $hook . '">' . $hook . '</option>'; |
|
2111
|
|
|
|
|
2112
|
|
|
if (!empty($hooks_filters)) |
|
2113
|
|
|
$context['insert_after_template'] .= ' |
|
2114
|
|
|
<script> |
|
2115
|
|
|
var hook_name_header = document.getElementById(\'header_list_integration_hooks_hook_name\'); |
|
2116
|
|
|
hook_name_header.innerHTML += ' . JavaScriptEscape('<select style="margin-left:15px;" onchange="window.location=(\'' . $scripturl . '?action=admin;area=maintain;sa=hooks\' + (this.value ? \';filter=\' + this.value : \'\'));"><option value="">' . $txt['hooks_reset_filter'] . '</option>' . implode('', $hooks_filters) . '</select>'). '; |
|
2117
|
|
|
</script>'; |
|
2118
|
|
|
|
|
2119
|
|
|
$temp_data = array(); |
|
2120
|
|
|
$id = 0; |
|
2121
|
|
|
|
|
2122
|
|
|
foreach ($hooks as $hook => $functions) |
|
2123
|
|
|
{ |
|
2124
|
|
|
if (empty($context['filter']) || (!empty($context['filter']) && $context['filter'] == $hook)) |
|
2125
|
|
|
{ |
|
2126
|
|
|
foreach ($functions as $rawFunc) |
|
2127
|
|
|
{ |
|
2128
|
|
|
// Get the hook info. |
|
2129
|
|
|
$hookParsedData = get_hook_info_from_raw($rawFunc); |
|
2130
|
|
|
|
|
2131
|
|
|
$hook_exists = !empty($hook_status[$hook][$hookParsedData['pureFunc']]['exists']); |
|
2132
|
|
|
$file_name = isset($hook_status[$hook][$hookParsedData['pureFunc']]['in_file']) ? $hook_status[$hook][$hookParsedData['pureFunc']]['in_file'] : ((substr($hook, -8) === '_include') ? basename($rawFunc) : $hookParsedData['hookFile']); |
|
|
|
|
|
|
2133
|
|
|
$sort[] = $sort_options[0]; |
|
2134
|
|
|
|
|
2135
|
|
|
$temp_data[] = array( |
|
2136
|
|
|
'id' => 'hookid_' . $id++, |
|
2137
|
|
|
'hook_name' => $hook, |
|
2138
|
|
|
'function_name' => $hookParsedData['rawData'], |
|
2139
|
|
|
'real_function' => $hookParsedData['pureFunc'], |
|
2140
|
|
|
'included_file' => !empty($hookParsedData['absPath']) ? $hookParsedData['absPath'] : '', |
|
2141
|
|
|
'file_name' => (isset($hook_status[$hook][$hookParsedData['pureFunc']]['in_file']) ? $hook_status[$hook][$hookParsedData['pureFunc']]['in_file'] : (!empty($hookParsedData['hookFile']) ? $hookParsedData['hookFile'] : '')), |
|
2142
|
|
|
'instance' => $hookParsedData['object'], |
|
2143
|
|
|
'hook_exists' => $hook_exists, |
|
2144
|
|
|
'status' => $hook_exists ? ($hookParsedData['enabled'] ? 'allow' : 'moderate') : 'deny', |
|
2145
|
|
|
'img_text' => $txt['hooks_' . ($hook_exists ? ($hookParsedData['enabled'] ? 'active' : 'disabled') : 'missing')], |
|
2146
|
|
|
'enabled' => $hookParsedData['enabled'], |
|
2147
|
|
|
'can_be_disabled' => !isset($hook_status[$hook][$hookParsedData['pureFunc']]['enabled']), |
|
2148
|
|
|
); |
|
2149
|
|
|
} |
|
2150
|
|
|
} |
|
2151
|
|
|
} |
|
2152
|
|
|
|
|
2153
|
|
|
array_multisort($sort, $sort_options[1], $temp_data); |
|
2154
|
|
|
|
|
2155
|
|
|
$counter = 0; |
|
2156
|
|
|
$start++; |
|
2157
|
|
|
|
|
2158
|
|
|
foreach ($temp_data as $data) |
|
2159
|
|
|
{ |
|
2160
|
|
|
if (++$counter < $start) |
|
2161
|
|
|
continue; |
|
2162
|
|
|
elseif ($counter == $start + $per_page) |
|
2163
|
|
|
break; |
|
2164
|
|
|
|
|
2165
|
|
|
$hooks_data[] = $data; |
|
2166
|
|
|
} |
|
2167
|
|
|
|
|
2168
|
|
|
return $hooks_data; |
|
2169
|
|
|
} |
|
2170
|
|
|
|
|
2171
|
|
|
/** |
|
2172
|
|
|
* Simply returns the total count of integration hooks |
|
2173
|
|
|
* Used by the integration hooks list function (list_integration_hooks) |
|
2174
|
|
|
* |
|
2175
|
|
|
* @return int The number of hooks currently in use |
|
2176
|
|
|
*/ |
|
2177
|
|
|
function get_integration_hooks_count() |
|
2178
|
|
|
{ |
|
2179
|
|
|
global $context; |
|
2180
|
|
|
|
|
2181
|
|
|
$hooks = get_integration_hooks(); |
|
2182
|
|
|
$hooks_count = 0; |
|
2183
|
|
|
|
|
2184
|
|
|
$context['filter'] = false; |
|
2185
|
|
|
if (isset($_GET['filter'])) |
|
2186
|
|
|
$context['filter'] = $_GET['filter']; |
|
2187
|
|
|
|
|
2188
|
|
|
foreach ($hooks as $hook => $functions) |
|
2189
|
|
|
{ |
|
2190
|
|
|
if (empty($context['filter']) || (!empty($context['filter']) && $context['filter'] == $hook)) |
|
2191
|
|
|
$hooks_count += count($functions); |
|
2192
|
|
|
} |
|
2193
|
|
|
|
|
2194
|
|
|
return $hooks_count; |
|
2195
|
|
|
} |
|
2196
|
|
|
|
|
2197
|
|
|
/** |
|
2198
|
|
|
* Parses modSettings to create integration hook array |
|
2199
|
|
|
* |
|
2200
|
|
|
* @return array An array of information about the integration hooks |
|
2201
|
|
|
*/ |
|
2202
|
|
|
function get_integration_hooks() |
|
2203
|
|
|
{ |
|
2204
|
|
|
global $modSettings; |
|
2205
|
|
|
static $integration_hooks; |
|
2206
|
|
|
|
|
2207
|
|
|
if (!isset($integration_hooks)) |
|
2208
|
|
|
{ |
|
2209
|
|
|
$integration_hooks = array(); |
|
2210
|
|
|
foreach ($modSettings as $key => $value) |
|
2211
|
|
|
{ |
|
2212
|
|
|
if (!empty($value) && substr($key, 0, 10) === 'integrate_') |
|
2213
|
|
|
$integration_hooks[$key] = explode(',', $value); |
|
2214
|
|
|
} |
|
2215
|
|
|
} |
|
2216
|
|
|
|
|
2217
|
|
|
return $integration_hooks; |
|
2218
|
|
|
} |
|
2219
|
|
|
|
|
2220
|
|
|
/** |
|
2221
|
|
|
* Parses each hook data and returns an array. |
|
2222
|
|
|
* |
|
2223
|
|
|
* @param string $rawData A string as it was saved to the DB. |
|
2224
|
|
|
* @return array everything found in the string itself |
|
2225
|
|
|
*/ |
|
2226
|
|
|
function get_hook_info_from_raw($rawData) |
|
2227
|
|
|
{ |
|
2228
|
|
|
global $boarddir, $settings, $sourcedir; |
|
2229
|
|
|
|
|
2230
|
|
|
// A single string can hold tons of info! |
|
2231
|
|
|
$hookData = array( |
|
2232
|
|
|
'object' => false, |
|
2233
|
|
|
'enabled' => true, |
|
2234
|
|
|
'fileExists' => false, |
|
2235
|
|
|
'absPath' => '', |
|
2236
|
|
|
'hookFile' => '', |
|
2237
|
|
|
'pureFunc' => '', |
|
2238
|
|
|
'method' => '', |
|
2239
|
|
|
'class' => '', |
|
2240
|
|
|
'rawData' => $rawData, |
|
2241
|
|
|
); |
|
2242
|
|
|
|
|
2243
|
|
|
// Meh... |
|
2244
|
|
|
if (empty($rawData)) |
|
2245
|
|
|
return $hookData; |
|
2246
|
|
|
|
|
2247
|
|
|
// For convenience purposes only! |
|
2248
|
|
|
$modFunc = $rawData; |
|
2249
|
|
|
|
|
2250
|
|
|
// Any files? |
|
2251
|
|
|
if (strpos($modFunc, '|') !== false) |
|
2252
|
|
|
{ |
|
2253
|
|
|
list ($hookData['hookFile'], $modFunc) = explode('|', $modFunc); |
|
2254
|
|
|
|
|
2255
|
|
|
// Does the file exists? who knows! |
|
2256
|
|
|
if (empty($settings['theme_dir'])) |
|
2257
|
|
|
$hookData['absPath'] = strtr(trim($hookData['hookFile']), array('$boarddir' => $boarddir, '$sourcedir' => $sourcedir)); |
|
2258
|
|
|
|
|
2259
|
|
|
else |
|
2260
|
|
|
$hookData['absPath'] = strtr(trim($hookData['hookFile']), array('$boarddir' => $boarddir, '$sourcedir' => $sourcedir, '$themedir' => $settings['theme_dir'])); |
|
2261
|
|
|
|
|
2262
|
|
|
$hookData['fileExists'] = file_exists($hookData['absPath']); |
|
2263
|
|
|
$hookData['hookFile'] = basename($hookData['hookFile']); |
|
2264
|
|
|
} |
|
2265
|
|
|
|
|
2266
|
|
|
// Hook is an instance. |
|
2267
|
|
View Code Duplication |
if (strpos($modFunc, '#') !== false) |
|
|
|
|
|
|
2268
|
|
|
{ |
|
2269
|
|
|
$modFunc = str_replace('#', '', $modFunc); |
|
2270
|
|
|
$hookData['object'] = true; |
|
2271
|
|
|
} |
|
2272
|
|
|
|
|
2273
|
|
|
// Hook is "disabled" |
|
2274
|
|
View Code Duplication |
if (strpos($modFunc, '!') !== false) |
|
|
|
|
|
|
2275
|
|
|
{ |
|
2276
|
|
|
$modFunc = str_replace('!', '', $modFunc); |
|
2277
|
|
|
$hookData['enabled'] = false; |
|
2278
|
|
|
} |
|
2279
|
|
|
|
|
2280
|
|
|
// Handling methods? |
|
2281
|
|
|
if (strpos($modFunc, '::') !== false) |
|
2282
|
|
|
{ |
|
2283
|
|
|
list ($hookData['class'], $hookData['method']) = explode('::', $modFunc); |
|
2284
|
|
|
$hookData['pureFunc'] = $hookData['method']; |
|
2285
|
|
|
} |
|
2286
|
|
|
|
|
2287
|
|
|
else |
|
2288
|
|
|
$hookData['pureFunc'] = $modFunc; |
|
2289
|
|
|
|
|
2290
|
|
|
return $hookData; |
|
2291
|
|
|
} |
|
2292
|
|
|
|
|
2293
|
|
|
?> |
|
|
|
|
|
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.