comparison forum/Sources/RepairBoards.php @ 76:e3e11437ecea website

Add forum code
author Chris Cannam
date Sun, 07 Jul 2013 11:25:48 +0200
parents
children
comparison
equal deleted inserted replaced
75:72f59aa7e503 76:e3e11437ecea
1 <?php
2
3 /**
4 * Simple Machines Forum (SMF)
5 *
6 * @package SMF
7 * @author Simple Machines http://www.simplemachines.org
8 * @copyright 2011 Simple Machines
9 * @license http://www.simplemachines.org/about/smf/license.php BSD
10 *
11 * @version 2.0
12 */
13
14 if (!defined('SMF'))
15 die('Hacking attempt...');
16
17 /* This is here for the "repair any errors" feature in the admin center. It
18 uses just two simple functions:
19
20 void RepairBoards()
21 - finds or repairs errors in the database to fix possible problems.
22 - requires the admin_forum permission.
23 - uses the raw_data sub template.
24 - calls createSalvageArea() to create a new board, if necesary.
25 - accessed by ?action=admin;area=repairboards.
26
27 void pauseRepairProcess(array to_fix, string current_step_desc, int max_substep = none, force = false)
28 - show the not_done template to avoid CGI timeouts and similar.
29 - called when 3 or more seconds have passed while searching for errors.
30 - if max_substep is set, $_GET['substep'] / $max_substep is the percent
31 done this step is.
32
33 array findForumErrors()
34 - checks for errors in steps, until 5 seconds have passed.
35 - keeps track of the errors it did find, so that the actual repair
36 won't have to recheck everything.
37 - returns the array of errors found.
38
39 void createSalvageArea()
40 - creates a salvage board/category if one doesn't already exist.
41 - uses the forum's default language, and checks based on that name.
42 */
43
44 function RepairBoards()
45 {
46 global $txt, $scripturl, $db_connection, $context, $sourcedir;
47 global $salvageCatID, $salvageBoardID, $smcFunc, $errorTests;
48
49 isAllowedTo('admin_forum');
50
51 // Try secure more memory.
52 @ini_set('memory_limit', '128M');
53
54 // Print out the top of the webpage.
55 $context['page_title'] = $txt['admin_repair'];
56 $context['sub_template'] = 'repair_boards';
57 $context[$context['admin_menu_name']]['current_subsection'] = 'general';
58
59 // Load the language file.
60 loadLanguage('ManageMaintenance');
61
62 // Make sure the tabs stay nice.
63 $context[$context['admin_menu_name']]['tab_data'] = array(
64 'title' => $txt['maintain_title'],
65 'help' => '',
66 'description' => $txt['maintain_info'],
67 'tabs' => array(),
68 );
69
70 // Start displaying errors without fixing them.
71 if (isset($_GET['fixErrors']))
72 checkSession('get');
73
74 // Will want this.
75 loadForumTests();
76
77 // Giant if/else. The first displays the forum errors if a variable is not set and asks
78 // if you would like to continue, the other fixes the errors.
79 if (!isset($_GET['fixErrors']))
80 {
81 $context['error_search'] = true;
82 $context['repair_errors'] = array();
83 $context['to_fix'] = findForumErrors();
84
85 if (!empty($context['to_fix']))
86 {
87 $_SESSION['repairboards_to_fix'] = $context['to_fix'];
88 $_SESSION['repairboards_to_fix2'] = null;
89
90 if (empty($context['repair_errors']))
91 $context['repair_errors'][] = '???';
92 }
93 }
94 else
95 {
96 $context['error_search'] = false;
97 $context['to_fix'] = isset($_SESSION['repairboards_to_fix']) ? $_SESSION['repairboards_to_fix'] : array();
98
99 require_once($sourcedir . '/Subs-Boards.php');
100
101 // Get the MySQL version for future reference.
102 $mysql_version = $smcFunc['db_server_info']($db_connection);
103
104 // Actually do the fix.
105 findForumErrors(true);
106
107 // Note that we've changed everything possible ;)
108 updateSettings(array(
109 'settings_updated' => time(),
110 ));
111 updateStats('message');
112 updateStats('topic');
113 updateSettings(array(
114 'calendar_updated' => time(),
115 ));
116
117 if (!empty($salvageBoardID))
118 {
119 $context['redirect_to_recount'] = true;
120 }
121
122 $_SESSION['repairboards_to_fix'] = null;
123 $_SESSION['repairboards_to_fix2'] = null;
124 }
125 }
126
127 function pauseRepairProcess($to_fix, $current_step_description, $max_substep = 0, $force = false)
128 {
129 global $context, $txt, $time_start, $db_temp_cache, $db_cache;
130
131 // More time, I need more time!
132 @set_time_limit(600);
133 if (function_exists('apache_reset_timeout'))
134 @apache_reset_timeout();
135
136 // Errr, wait. How much time has this taken already?
137 if (!$force && time() - array_sum(explode(' ', $time_start)) < 3)
138 return;
139
140 // Restore the query cache if interested.
141 if (!empty($db_temp_cache))
142 $db_cache = $db_temp_cache;
143
144 $context['continue_get_data'] = '?action=admin;area=repairboards' . (isset($_GET['fixErrors']) ? ';fixErrors' : '') . ';step=' . $_GET['step'] . ';substep=' . $_GET['substep'] . ';' . $context['session_var'] . '=' . $context['session_id'];
145 $context['page_title'] = $txt['not_done_title'];
146 $context['continue_post_data'] = '';
147 $context['continue_countdown'] = '2';
148 $context['sub_template'] = 'not_done';
149
150 // Change these two if more steps are added!
151 if (empty($max_substep))
152 $context['continue_percent'] = round(($_GET['step'] * 100) / $context['total_steps']);
153 else
154 $context['continue_percent'] = round((($_GET['step'] + ($_GET['substep'] / $max_substep)) * 100) / $context['total_steps']);
155
156 // Never more than 100%!
157 $context['continue_percent'] = min($context['continue_percent'], 100);
158
159 // What about substeps?
160 $context['substep_enabled'] = $max_substep != 0;
161 $context['substep_title'] = sprintf($txt['repair_currently_' . (isset($_GET['fixErrors']) ? 'fixing' : 'checking')], (isset($txt['repair_operation_' . $current_step_description]) ? $txt['repair_operation_' . $current_step_description] : $current_step_description));
162 $context['substep_continue_percent'] = $max_substep == 0 ? 0 : round(($_GET['substep'] * 100) / $max_substep, 1);
163
164 $_SESSION['repairboards_to_fix'] = $to_fix;
165 $_SESSION['repairboards_to_fix2'] = $context['repair_errors'];
166
167 obExit();
168 }
169
170 // Load up all the tests we might want to do ;)
171 function loadForumTests()
172 {
173 global $smcFunc, $errorTests;
174
175 /* Here this array is defined like so:
176 string check_query: Query to be executed when testing if errors exist.
177 string check_type: Defines how it knows if a problem was found. If set to count looks for the first variable from check_query
178 being > 0. Anything else it looks for some results. If not set assumes you want results.
179 string fix_it_query: When doing fixes if an error was detected this query is executed to "fix" it.
180 string fix_query: The query to execute to get data when doing a fix. If not set check_query is used again.
181 array fix_collect: This array is used if the fix is basically gathering all broken ids and then doing something with it.
182 - string index: The value returned from the main query and passed to the processing function.
183 - process: A function passed an array of ids to execute the fix on.
184 function fix_processing:
185 Function called for each row returned from fix_query to execute whatever fixes are required.
186 function fix_full_processing:
187 As above but does the while loop and everything itself - except the freeing.
188 array force_fix: If this is set then the error types included within this array will also be assumed broken.
189 Note: At the moment only processes these if they occur after the primary error in the array.
190 */
191
192 // This great array contains all of our error checks, fixes, etc etc etc.
193 $errorTests = array(
194 // Make a last-ditch-effort check to get rid of topics with zeros..
195 'zero_topics' => array(
196 'check_query' => '
197 SELECT COUNT(*)
198 FROM {db_prefix}topics
199 WHERE id_topic = 0',
200 'check_type' => 'count',
201 'fix_it_query' => '
202 UPDATE {db_prefix}topics
203 SET id_topic = NULL
204 WHERE id_topic = 0',
205 'message' => 'repair_zero_ids',
206 ),
207 // ... and same with messages.
208 'zero_messages' => array(
209 'check_query' => '
210 SELECT COUNT(*)
211 FROM {db_prefix}messages
212 WHERE id_msg = 0',
213 'check_type' => 'count',
214 'fix_it_query' => '
215 UPDATE {db_prefix}messages
216 SET id_msg = NULL
217 WHERE id_msg = 0',
218 'message' => 'repair_zero_ids',
219 ),
220 // Find messages that don't have existing topics.
221 'missing_topics' => array(
222 'substeps' => array(
223 'step_size' => 1000,
224 'step_max' => '
225 SELECT MAX(id_topic)
226 FROM {db_prefix}messages'
227 ),
228 'check_query' => '
229 SELECT m.id_topic, m.id_msg
230 FROM {db_prefix}messages AS m
231 LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
232 WHERE m.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
233 AND t.id_topic IS NULL
234 ORDER BY m.id_topic, m.id_msg',
235 'fix_query' => '
236 SELECT
237 m.id_board, m.id_topic, MIN(m.id_msg) AS myid_first_msg, MAX(m.id_msg) AS myid_last_msg,
238 COUNT(*) - 1 AS my_num_replies
239 FROM {db_prefix}messages AS m
240 LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
241 WHERE t.id_topic IS NULL
242 GROUP BY m.id_topic, m.id_board',
243 'fix_processing' => create_function('$row', '
244 global $smcFunc, $salvageBoardID;
245
246 // Only if we don\'t have a reasonable idea of where to put it.
247 if ($row[\'id_board\'] == 0)
248 {
249 createSalvageArea();
250 $row[\'id_board\'] = (int) $salvageBoardID;
251 }
252
253 // Make sure that no topics claim the first/last message as theirs.
254 $smcFunc[\'db_query\'](\'\', \'
255 UPDATE {db_prefix}topics
256 SET id_first_msg = 0
257 WHERE id_first_msg = {int:id_first_msg}\',
258 array(
259 \'id_first_msg\' => $row[\'myid_first_msg\'],
260 )
261 );
262 $smcFunc[\'db_query\'](\'\', \'
263 UPDATE {db_prefix}topics
264 SET id_last_msg = 0
265 WHERE id_last_msg = {int:id_last_msg}\',
266 array(
267 \'id_last_msg\' => $row[\'myid_last_msg\'],
268 )
269 );
270
271 $memberStartedID = (int) getMsgMemberID($row[\'myid_first_msg\']);
272 $memberUpdatedID = (int) getMsgMemberID($row[\'myid_last_msg\']);
273
274 $smcFunc[\'db_insert\'](\'\',
275 \'{db_prefix}topics\',
276 array(
277 \'id_board\' => \'int\',
278 \'id_member_started\' => \'int\',
279 \'id_member_updated\' => \'int\',
280 \'id_first_msg\' => \'int\',
281 \'id_last_msg\' => \'int\',
282 \'num_replies\' => \'int\'
283 ),
284 array(
285 $row[\'id_board\'],
286 $memberStartedID,
287 $memberUpdatedID,
288 $row[\'myid_first_msg\'],
289 $row[\'myid_last_msg\'],
290 $row[\'my_num_replies\']
291 ),
292 array(\'id_topic\')
293 );
294
295 $newTopicID = $smcFunc[\'db_insert_id\']("{db_prefix}topics", \'id_topic\');
296
297 $smcFunc[\'db_query\'](\'\', "
298 UPDATE {db_prefix}messages
299 SET id_topic = $newTopicID, id_board = $row[id_board]
300 WHERE id_topic = $row[id_topic]",
301 array(
302 )
303 );
304 '),
305 'force_fix' => array('stats_topics'),
306 'messages' => array('repair_missing_topics', 'id_msg', 'id_topic'),
307 ),
308 // Find topics with no messages.
309 'missing_messages' => array(
310 'substeps' => array(
311 'step_size' => 1000,
312 'step_max' => '
313 SELECT MAX(id_topic)
314 FROM {db_prefix}topics'
315 ),
316 'check_query' => '
317 SELECT t.id_topic, COUNT(m.id_msg) AS num_msg
318 FROM {db_prefix}topics AS t
319 LEFT JOIN {db_prefix}messages AS m ON (m.id_topic = t.id_topic)
320 WHERE t.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
321 GROUP BY t.id_topic
322 HAVING COUNT(m.id_msg) = 0',
323 // Remove all topics that have zero messages in the messages table.
324 'fix_collect' => array(
325 'index' => 'id_topic',
326 'process' => create_function('$topics', '
327 global $smcFunc;
328 $smcFunc[\'db_query\'](\'\', "
329 DELETE FROM {db_prefix}topics
330 WHERE id_topic IN ({array_int:topics})",
331 array(
332 \'topics\' => $topics
333 )
334 );
335 $smcFunc[\'db_query\'](\'\', "
336 DELETE FROM {db_prefix}log_topics
337 WHERE id_topic IN ({array_int:topics})",
338 array(
339 \'topics\' => $topics
340 )
341 );
342 '),
343 ),
344 'messages' => array('repair_missing_messages', 'id_topic'),
345 ),
346 'polls_missing_topics' => array(
347 'substeps' => array(
348 'step_size' => 500,
349 'step_max' => '
350 SELECT MAX(id_poll)
351 FROM {db_prefix}polls'
352 ),
353 'check_query' => '
354 SELECT p.id_poll, p.id_member, p.poster_name, t.id_board
355 FROM {db_prefix}polls AS p
356 LEFT JOIN {db_prefix}topics AS t ON (t.id_poll = p.id_poll)
357 WHERE p.id_poll BETWEEN {STEP_LOW} AND {STEP_HIGH}
358 AND t.id_poll IS NULL',
359 'fix_processing' => create_function('$row', '
360 global $smcFunc, $salvageBoardID, $txt;
361
362 // Only if we don\'t have a reasonable idea of where to put it.
363 if ($row[\'id_board\'] == 0)
364 {
365 createSalvageArea();
366 $row[\'id_board\'] = (int) $salvageBoardID;
367 }
368
369 $row[\'poster_name\'] = !empty($row[\'poster_name\']) ? $row[\'poster_name\'] : $txt[\'guest\'];
370
371 $smcFunc[\'db_insert\'](\'\',
372 \'{db_prefix}messages\',
373 array(
374 \'id_board\' => \'int\',
375 \'id_topic\' => \'int\',
376 \'poster_time\' => \'int\',
377 \'id_member\' => \'int\',
378 \'subject\' => \'string-255\',
379 \'poster_name\' => \'string-255\',
380 \'poster_email\' => \'string-255\',
381 \'poster_ip\' => \'string-16\',
382 \'smileys_enabled\' => \'int\',
383 \'body\' => \'string-65534\',
384 \'icon\' => \'string-16\',
385 \'approved\' => \'int\',
386 ),
387 array(
388 $row[\'id_board\'],
389 0,
390 time(),
391 $row[\'id_member\'],
392 $txt[\'salvaged_poll_topic_name\'],
393 $row[\'poster_name\'],
394 \'\',
395 \'127.0.0.1\',
396 1,
397 $txt[\'salvaged_poll_message_body\'],
398 \'xx\',
399 1,
400 ),
401 array(\'id_topic\')
402 );
403
404 $newMessageID = $smcFunc[\'db_insert_id\']("{db_prefix}messages", \'id_msg\');
405
406 $smcFunc[\'db_insert\'](\'\',
407 \'{db_prefix}topics\',
408 array(
409 \'id_board\' => \'int\',
410 \'id_poll\' => \'int\',
411 \'id_member_started\' => \'int\',
412 \'id_member_updated\' => \'int\',
413 \'id_first_msg\' => \'int\',
414 \'id_last_msg\' => \'int\',
415 \'num_replies\' => \'int\',
416 ),
417 array(
418 $row[\'id_board\'],
419 $row[\'id_poll\'],
420 $row[\'id_member\'],
421 $row[\'id_member\'],
422 $newMessageID,
423 $newMessageID,
424 0,
425 ),
426 array(\'id_topic\')
427 );
428
429 $newTopicID = $smcFunc[\'db_insert_id\']("{db_prefix}topics", \'id_topic\');
430
431 $smcFunc[\'db_query\'](\'\', "
432 UPDATE {db_prefix}messages
433 SET id_topic = $newTopicID, id_board = $row[id_board]
434 WHERE id_msg = $newMessageID",
435 array(
436 )
437 );
438
439 updateStats(\'subject\', $newTopicID, $txt[\'salvaged_poll_topic_name\']);
440
441 '),
442 'force_fix' => array('stats_topics'),
443 'messages' => array('repair_polls_missing_topics', 'id_poll', 'id_topic'),
444 ),
445 'stats_topics' => array(
446 'substeps' => array(
447 'step_size' => 200,
448 'step_max' => '
449 SELECT MAX(id_topic)
450 FROM {db_prefix}topics'
451 ),
452 'check_query' => '
453 SELECT
454 t.id_topic, t.id_first_msg, t.id_last_msg,
455 CASE WHEN MIN(ma.id_msg) > 0 THEN
456 CASE WHEN MIN(mu.id_msg) > 0 THEN
457 CASE WHEN MIN(mu.id_msg) < MIN(ma.id_msg) THEN MIN(mu.id_msg) ELSE MIN(ma.id_msg) END ELSE
458 MIN(ma.id_msg) END ELSE
459 MIN(mu.id_msg) END AS myid_first_msg,
460 CASE WHEN MAX(ma.id_msg) > 0 THEN MAX(ma.id_msg) ELSE MIN(mu.id_msg) END AS myid_last_msg,
461 t.approved, mf.approved, mf.approved AS firstmsg_approved
462 FROM {db_prefix}topics AS t
463 LEFT JOIN {db_prefix}messages AS ma ON (ma.id_topic = t.id_topic AND ma.approved = 1)
464 LEFT JOIN {db_prefix}messages AS mu ON (mu.id_topic = t.id_topic AND mu.approved = 0)
465 LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
466 WHERE t.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
467 GROUP BY t.id_topic, t.id_first_msg, t.id_last_msg, t.approved, mf.approved
468 ORDER BY t.id_topic',
469 'fix_processing' => create_function('$row', '
470 global $smcFunc;
471 $row[\'firstmsg_approved\'] = (int) $row[\'firstmsg_approved\'];
472 $row[\'myid_first_msg\'] = (int) $row[\'myid_first_msg\'];
473 $row[\'myid_last_msg\'] = (int) $row[\'myid_last_msg\'];
474
475 // Not really a problem?
476 if ($row[\'myid_first_msg\'] == $row[\'myid_first_msg\'] && $row[\'myid_first_msg\'] == $row[\'myid_first_msg\'] && $row[\'approved\'] == $row[\'firstmsg_approved\'])
477 return false;
478
479 $memberStartedID = (int) getMsgMemberID($row[\'myid_first_msg\']);
480 $memberUpdatedID = (int) getMsgMemberID($row[\'myid_last_msg\']);
481
482 $smcFunc[\'db_query\'](\'\', "
483 UPDATE {db_prefix}topics
484 SET id_first_msg = $row[myid_first_msg],
485 id_member_started = $memberStartedID, id_last_msg = $row[myid_last_msg],
486 id_member_updated = $memberUpdatedID, approved = $row[firstmsg_approved]
487 WHERE id_topic = $row[id_topic]",
488 array(
489 )
490 );
491 '),
492 'message_function' => create_function('$row', '
493 global $txt, $context;
494
495 // A pretend error?
496 if ($row[\'myid_first_msg\'] == $row[\'myid_first_msg\'] && $row[\'myid_first_msg\'] == $row[\'myid_first_msg\'] && $row[\'approved\'] == $row[\'firstmsg_approved\'])
497 return false;
498
499 if ($row[\'id_first_msg\'] != $row[\'myid_first_msg\'])
500 $context[\'repair_errors\'][] = sprintf($txt[\'repair_stats_topics_1\'], $row[\'id_topic\'], $row[\'id_first_msg\']);
501 if ($row[\'id_last_msg\'] != $row[\'myid_last_msg\'])
502 $context[\'repair_errors\'][] = sprintf($txt[\'repair_stats_topics_2\'], $row[\'id_topic\'], $row[\'id_last_msg\']);
503 if ($row[\'approved\'] != $row[\'firstmsg_approved\'])
504 $context[\'repair_errors\'][] = sprintf($txt[\'repair_stats_topics_5\'], $row[\'id_topic\']);
505
506 return true;
507 '),
508 ),
509 // Find topics with incorrect num_replies.
510 'stats_topics2' => array(
511 'substeps' => array(
512 'step_size' => 300,
513 'step_max' => '
514 SELECT MAX(id_topic)
515 FROM {db_prefix}topics'
516 ),
517 'check_query' => '
518 SELECT
519 t.id_topic, t.num_replies, mf.approved,
520 CASE WHEN COUNT(ma.id_msg) > 0 THEN CASE WHEN mf.approved > 0 THEN COUNT(ma.id_msg) - 1 ELSE COUNT(ma.id_msg) END ELSE 0 END AS my_num_replies
521 FROM {db_prefix}topics AS t
522 LEFT JOIN {db_prefix}messages AS ma ON (ma.id_topic = t.id_topic AND ma.approved = 1)
523 LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
524 WHERE t.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
525 GROUP BY t.id_topic, t.num_replies, mf.approved
526 ORDER BY t.id_topic',
527 'fix_processing' => create_function('$row', '
528 global $smcFunc;
529 $row[\'my_num_replies\'] = (int) $row[\'my_num_replies\'];
530
531 // Not really a problem?
532 if ($row[\'my_num_replies\'] == $row[\'num_replies\'])
533 return false;
534
535 $smcFunc[\'db_query\'](\'\', "
536 UPDATE {db_prefix}topics
537 SET num_replies = $row[my_num_replies]
538 WHERE id_topic = $row[id_topic]",
539 array(
540 )
541 );
542 '),
543 'message_function' => create_function('$row', '
544 global $txt, $context;
545
546 // Just joking?
547 if ($row[\'my_num_replies\'] == $row[\'num_replies\'])
548 return false;
549
550 if ($row[\'num_replies\'] != $row[\'my_num_replies\'])
551 $context[\'repair_errors\'][] = sprintf($txt[\'repair_stats_topics_3\'], $row[\'id_topic\'], $row[\'num_replies\']);
552
553 return true;
554 '),
555 ),
556 // Find topics with incorrect unapproved_posts.
557 'stats_topics3' => array(
558 'substeps' => array(
559 'step_size' => 1000,
560 'step_max' => '
561 SELECT MAX(id_topic)
562 FROM {db_prefix}topics'
563 ),
564 'check_query' => '
565 SELECT
566 t.id_topic, t.unapproved_posts, COUNT(mu.id_msg) AS my_unapproved_posts
567 FROM {db_prefix}topics AS t
568 LEFT JOIN {db_prefix}messages AS mu ON (mu.id_topic = t.id_topic AND mu.approved = 0)
569 WHERE t.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
570 GROUP BY t.id_topic, t.unapproved_posts
571 HAVING unapproved_posts != COUNT(mu.id_msg)
572 ORDER BY t.id_topic',
573 'fix_processing' => create_function('$row', '
574 global $smcFunc;
575 $row[\'my_unapproved_posts\'] = (int) $row[\'my_unapproved_posts\'];
576
577 $smcFunc[\'db_query\'](\'\', "
578 UPDATE {db_prefix}topics
579 SET unapproved_posts = $row[my_unapproved_posts]
580 WHERE id_topic = $row[id_topic]",
581 array(
582 )
583 );
584 '),
585 'messages' => array('repair_stats_topics_4', 'id_topic', 'unapproved_posts'),
586 ),
587 // Find topics with nonexistent boards.
588 'missing_boards' => array(
589 'substeps' => array(
590 'step_size' => 1000,
591 'step_max' => '
592 SELECT MAX(id_topic)
593 FROM {db_prefix}topics'
594 ),
595 'check_query' => '
596 SELECT t.id_topic, t.id_board
597 FROM {db_prefix}topics AS t
598 LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
599 WHERE b.id_board IS NULL
600 AND t.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
601 ORDER BY t.id_board, t.id_topic',
602 'fix_query' => '
603 SELECT t.id_board, COUNT(*) AS my_num_topics, COUNT(m.id_msg) AS my_num_posts
604 FROM {db_prefix}topics AS t
605 LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
606 LEFT JOIN {db_prefix}messages AS m ON (m.id_topic = t.id_topic)
607 WHERE b.id_board IS NULL
608 AND t.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
609 GROUP BY t.id_board',
610 'fix_processing' => create_function('$row', '
611 global $smcFunc, $salvageCatID;
612 createSalvageArea();
613
614 $row[\'my_num_topics\'] = (int) $row[\'my_num_topics\'];
615 $row[\'my_num_posts\'] = (int) $row[\'my_num_posts\'];
616
617 $smcFunc[\'db_insert\'](\'\',
618 \'{db_prefix}boards\',
619 array(\'id_cat\' => \'int\', \'name\' => \'string\', \'description\' => \'string\', \'num_topics\' => \'int\', \'num_posts\' => \'int\', \'member_groups\' => \'string\'),
620 array($salvageCatID, \'Salvaged board\', \'\', $row[\'my_num_topics\'], $row[\'my_num_posts\'], \'1\'),
621 array(\'id_board\')
622 );
623 $newBoardID = $smcFunc[\'db_insert_id\'](\'{db_prefix}boards\', \'id_board\');
624
625 $smcFunc[\'db_query\'](\'\', "
626 UPDATE {db_prefix}topics
627 SET id_board = $newBoardID
628 WHERE id_board = $row[id_board]",
629 array(
630 )
631 );
632 $smcFunc[\'db_query\'](\'\', "
633 UPDATE {db_prefix}messages
634 SET id_board = $newBoardID
635 WHERE id_board = $row[id_board]",
636 array(
637 )
638 );
639 '),
640 'messages' => array('repair_missing_boards', 'id_topic', 'id_board'),
641 ),
642 // Find boards with nonexistent categories.
643 'missing_categories' => array(
644 'check_query' => '
645 SELECT b.id_board, b.id_cat
646 FROM {db_prefix}boards AS b
647 LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
648 WHERE c.id_cat IS NULL
649 ORDER BY b.id_cat, b.id_board',
650 'fix_collect' => array(
651 'index' => 'id_cat',
652 'process' => create_function('$cats', '
653 global $smcFunc, $salvageCatID;
654 createSalvageArea();
655 $smcFunc[\'db_query\'](\'\', "
656 UPDATE {db_prefix}boards
657 SET id_cat = $salvageCatID
658 WHERE id_cat IN ({array_int:categories})",
659 array(
660 \'categories\' => $cats
661 )
662 );
663 '),
664 ),
665 'messages' => array('repair_missing_categories', 'id_board', 'id_cat'),
666 ),
667 // Find messages with nonexistent members.
668 'missing_posters' => array(
669 'substeps' => array(
670 'step_size' => 2000,
671 'step_max' => '
672 SELECT MAX(id_msg)
673 FROM {db_prefix}messages'
674 ),
675 'check_query' => '
676 SELECT m.id_msg, m.id_member
677 FROM {db_prefix}messages AS m
678 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
679 WHERE mem.id_member IS NULL
680 AND m.id_member != 0
681 AND m.id_msg BETWEEN {STEP_LOW} AND {STEP_HIGH}
682 ORDER BY m.id_msg',
683 // Last step-make sure all non-guest posters still exist.
684 'fix_collect' => array(
685 'index' => 'id_msg',
686 'process' => create_function('$msgs', '
687 global $smcFunc;
688 $smcFunc[\'db_query\'](\'\', "
689 UPDATE {db_prefix}messages
690 SET id_member = 0
691 WHERE id_msg IN ({array_int:msgs})",
692 array(
693 \'msgs\' => $msgs
694 )
695 );
696 '),
697 ),
698 'messages' => array('repair_missing_posters', 'id_msg', 'id_member'),
699 ),
700 // Find boards with nonexistent parents.
701 'missing_parents' => array(
702 'check_query' => '
703 SELECT b.id_board, b.id_parent
704 FROM {db_prefix}boards AS b
705 LEFT JOIN {db_prefix}boards AS p ON (p.id_board = b.id_parent)
706 WHERE b.id_parent != 0
707 AND (p.id_board IS NULL OR p.id_board = b.id_board)
708 ORDER BY b.id_parent, b.id_board',
709 'fix_collect' => array(
710 'index' => 'id_parent',
711 'process' => create_function('$parents', '
712 global $smcFunc, $salvageBoardID, $salvageCatID;
713 createSalvageArea();
714 $smcFunc[\'db_query\'](\'\', "
715 UPDATE {db_prefix}boards
716 SET id_parent = $salvageBoardID, id_cat = $salvageCatID, child_level = 1
717 WHERE id_parent IN ({array_int:parents})",
718 array(
719 \'parents\' => $parents
720 )
721 );
722 '),
723 ),
724 'messages' => array('repair_missing_parents', 'id_board', 'id_parent'),
725 ),
726 'missing_polls' => array(
727 'substeps' => array(
728 'step_size' => 500,
729 'step_max' => '
730 SELECT MAX(id_poll)
731 FROM {db_prefix}topics'
732 ),
733 'check_query' => '
734 SELECT t.id_poll, t.id_topic
735 FROM {db_prefix}topics AS t
736 LEFT JOIN {db_prefix}polls AS p ON (p.id_poll = t.id_poll)
737 WHERE t.id_poll != 0
738 AND t.id_poll BETWEEN {STEP_LOW} AND {STEP_HIGH}
739 AND p.id_poll IS NULL',
740 'fix_collect' => array(
741 'index' => 'id_poll',
742 'process' => create_function('$polls', '
743 global $smcFunc;
744 $smcFunc[\'db_query\'](\'\', "
745 UPDATE {db_prefix}topics
746 SET id_poll = 0
747 WHERE id_poll IN ({array_int:polls})",
748 array(
749 \'polls\' => $polls
750 )
751 );
752 '),
753 ),
754 'messages' => array('repair_missing_polls', 'id_topic', 'id_poll'),
755 ),
756 'missing_calendar_topics' => array(
757 'substeps' => array(
758 'step_size' => 1000,
759 'step_max' => '
760 SELECT MAX(id_topic)
761 FROM {db_prefix}calendar'
762 ),
763 'check_query' => '
764 SELECT cal.id_topic, cal.id_event
765 FROM {db_prefix}calendar AS cal
766 LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = cal.id_topic)
767 WHERE cal.id_topic != 0
768 AND cal.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
769 AND t.id_topic IS NULL
770 ORDER BY cal.id_topic',
771 'fix_collect' => array(
772 'index' => 'id_topic',
773 'process' => create_function('$events', '
774 global $smcFunc;
775 $smcFunc[\'db_query\'](\'\', \'
776 UPDATE {db_prefix}calendar
777 SET id_topic = 0, id_board = 0
778 WHERE id_topic IN ({array_int:events})\',
779 array(
780 \'events\' => $events
781 )
782 );
783 '),
784 ),
785 'messages' => array('repair_missing_calendar_topics', 'id_event', 'id_topic'),
786 ),
787 'missing_log_topics' => array(
788 'substeps' => array(
789 'step_size' => 150,
790 'step_max' => '
791 SELECT MAX(id_member)
792 FROM {db_prefix}log_topics'
793 ),
794 'check_query' => '
795 SELECT lt.id_topic
796 FROM {db_prefix}log_topics AS lt
797 LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = lt.id_topic)
798 WHERE t.id_topic IS NULL
799 AND lt.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}',
800 'fix_collect' => array(
801 'index' => 'id_topic',
802 'process' => create_function('$topics', '
803 global $smcFunc;
804 $smcFunc[\'db_query\'](\'\', "
805 DELETE FROM {db_prefix}log_topics
806 WHERE id_topic IN ({array_int:topics})",
807 array(
808 \'topics\' => $topics
809 )
810 );
811 '),
812 ),
813 'messages' => array('repair_missing_log_topics', 'id_topic'),
814 ),
815 'missing_log_topics_members' => array(
816 'substeps' => array(
817 'step_size' => 150,
818 'step_max' => '
819 SELECT MAX(id_member)
820 FROM {db_prefix}log_topics'
821 ),
822 'check_query' => '
823 SELECT lt.id_member
824 FROM {db_prefix}log_topics AS lt
825 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lt.id_member)
826 WHERE mem.id_member IS NULL
827 AND lt.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}
828 GROUP BY lt.id_member',
829 'fix_collect' => array(
830 'index' => 'id_member',
831 'process' => create_function('$members', '
832 global $smcFunc;
833 $smcFunc[\'db_query\'](\'\', "
834 DELETE FROM {db_prefix}log_topics
835 WHERE id_member IN ({array_int:members})",
836 array(
837 \'members\' => $members
838 )
839 );
840 '),
841 ),
842 'messages' => array('repair_missing_log_topics_members', 'id_member'),
843 ),
844 'missing_log_boards' => array(
845 'substeps' => array(
846 'step_size' => 500,
847 'step_max' => '
848 SELECT MAX(id_member)
849 FROM {db_prefix}log_boards'
850 ),
851 'check_query' => '
852 SELECT lb.id_board
853 FROM {db_prefix}log_boards AS lb
854 LEFT JOIN {db_prefix}boards AS b ON (b.id_board = lb.id_board)
855 WHERE b.id_board IS NULL
856 AND lb.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}
857 GROUP BY lb.id_board',
858 'fix_collect' => array(
859 'index' => 'id_board',
860 'process' => create_function('$boards', '
861 global $smcFunc;
862 $smcFunc[\'db_query\'](\'\', "
863 DELETE FROM {db_prefix}log_boards
864 WHERE id_board IN ({array_int:boards})",
865 array(
866 \'boards\' => $boards
867 )
868 );
869 '),
870 ),
871 'messages' => array('repair_missing_log_boards', 'id_board'),
872 ),
873 'missing_log_boards_members' => array(
874 'substeps' => array(
875 'step_size' => 500,
876 'step_max' => '
877 SELECT MAX(id_member)
878 FROM {db_prefix}log_boards'
879 ),
880 'check_query' => '
881 SELECT lb.id_member
882 FROM {db_prefix}log_boards AS lb
883 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lb.id_member)
884 WHERE mem.id_member IS NULL
885 AND lb.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}
886 GROUP BY lb.id_member',
887 'fix_collect' => array(
888 'index' => 'id_member',
889 'process' => create_function('$members', '
890 global $smcFunc;
891 $smcFunc[\'db_query\'](\'\', "
892 DELETE FROM {db_prefix}log_boards
893 WHERE id_member IN ({array_int:members})",
894 array(
895 \'members\' => $members
896 )
897 );
898 '),
899 ),
900 'messages' => array('repair_missing_log_boards_members', 'id_member'),
901 ),
902 'missing_log_mark_read' => array(
903 'substeps' => array(
904 'step_size' => 500,
905 'step_max' => '
906 SELECT MAX(id_member)
907 FROM {db_prefix}log_mark_read'
908 ),
909 'check_query' => '
910 SELECT lmr.id_board
911 FROM {db_prefix}log_mark_read AS lmr
912 LEFT JOIN {db_prefix}boards AS b ON (b.id_board = lmr.id_board)
913 WHERE b.id_board IS NULL
914 AND lmr.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}
915 GROUP BY lmr.id_board',
916 'fix_collect' => array(
917 'index' => 'id_board',
918 'process' => create_function('$boards', '
919 global $smcFunc;
920 $smcFunc[\'db_query\'](\'\', "
921 DELETE FROM {db_prefix}log_mark_read
922 WHERE id_board IN ({array_int:boards})",
923 array(
924 \'boards\' => $boards
925 )
926 );
927 '),
928 ),
929 'messages' => array('repair_missing_log_mark_read', 'id_board'),
930 ),
931 'missing_log_mark_read_members' => array(
932 'substeps' => array(
933 'step_size' => 500,
934 'step_max' => '
935 SELECT MAX(id_member)
936 FROM {db_prefix}log_mark_read'
937 ),
938 'check_query' => '
939 SELECT lmr.id_member
940 FROM {db_prefix}log_mark_read AS lmr
941 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lmr.id_member)
942 WHERE mem.id_member IS NULL
943 AND lmr.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}
944 GROUP BY lmr.id_member',
945 'fix_collect' => array(
946 'index' => 'id_member',
947 'process' => create_function('$members', '
948 global $smcFunc;
949 $smcFunc[\'db_query\'](\'\', "
950 DELETE FROM {db_prefix}log_mark_read
951 WHERE id_member IN ({array_int:members})",
952 array(
953 \'members\' => $members
954 )
955 );
956 '),
957 ),
958 'messages' => array('repair_missing_log_mark_read_members', 'id_member'),
959 ),
960 'missing_pms' => array(
961 'substeps' => array(
962 'step_size' => 500,
963 'step_max' => '
964 SELECT MAX(id_pm)
965 FROM {db_prefix}pm_recipients'
966 ),
967 'check_query' => '
968 SELECT pmr.id_pm
969 FROM {db_prefix}pm_recipients AS pmr
970 LEFT JOIN {db_prefix}personal_messages AS pm ON (pm.id_pm = pmr.id_pm)
971 WHERE pm.id_pm IS NULL
972 AND pmr.id_pm BETWEEN {STEP_LOW} AND {STEP_HIGH}
973 GROUP BY pmr.id_pm',
974 'fix_collect' => array(
975 'index' => 'id_pm',
976 'process' => create_function('$pms', '
977 global $smcFunc;
978 $smcFunc[\'db_query\'](\'\', "
979 DELETE FROM {db_prefix}pm_recipients
980 WHERE id_pm IN ({array_int:pms})",
981 array(
982 \'pms\' => $pms
983 )
984 );
985 '),
986 ),
987 'messages' => array('repair_missing_pms', 'id_pm'),
988 ),
989 'missing_recipients' => array(
990 'substeps' => array(
991 'step_size' => 500,
992 'step_max' => '
993 SELECT MAX(id_member)
994 FROM {db_prefix}pm_recipients'
995 ),
996 'check_query' => '
997 SELECT pmr.id_member
998 FROM {db_prefix}pm_recipients AS pmr
999 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = pmr.id_member)
1000 WHERE pmr.id_member != 0
1001 AND pmr.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}
1002 AND mem.id_member IS NULL
1003 GROUP BY pmr.id_member',
1004 'fix_collect' => array(
1005 'index' => 'id_member',
1006 'process' => create_function('$members', '
1007 global $smcFunc;
1008 $smcFunc[\'db_query\'](\'\', "
1009 DELETE FROM {db_prefix}pm_recipients
1010 WHERE id_member IN ({array_int:members})",
1011 array(
1012 \'members\' => $members
1013 )
1014 );
1015 '),
1016 ),
1017 'messages' => array('repair_missing_recipients', 'id_member'),
1018 ),
1019 'missing_senders' => array(
1020 'substeps' => array(
1021 'step_size' => 500,
1022 'step_max' => '
1023 SELECT MAX(id_pm)
1024 FROM {db_prefix}personal_messages'
1025 ),
1026 'check_query' => '
1027 SELECT pm.id_pm, pm.id_member_from
1028 FROM {db_prefix}personal_messages AS pm
1029 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = pm.id_member_from)
1030 WHERE pm.id_member_from != 0
1031 AND pm.id_pm BETWEEN {STEP_LOW} AND {STEP_HIGH}
1032 AND mem.id_member IS NULL',
1033 'fix_collect' => array(
1034 'index' => 'id_pm',
1035 'process' => create_function('$guestMessages', '
1036 global $smcFunc;
1037 $smcFunc[\'db_query\'](\'\', "
1038 UPDATE {db_prefix}personal_messages
1039 SET id_member_from = 0
1040 WHERE id_pm IN ({array_int:guestMessages})",
1041 array(
1042 \'guestMessages\' => $guestMessages
1043 ));
1044 '),
1045 ),
1046 'messages' => array('repair_missing_senders', 'id_pm', 'id_member_from'),
1047 ),
1048 'missing_notify_members' => array(
1049 'substeps' => array(
1050 'step_size' => 500,
1051 'step_max' => '
1052 SELECT MAX(id_member)
1053 FROM {db_prefix}log_notify'
1054 ),
1055 'check_query' => '
1056 SELECT ln.id_member
1057 FROM {db_prefix}log_notify AS ln
1058 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ln.id_member)
1059 WHERE ln.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}
1060 AND mem.id_member IS NULL
1061 GROUP BY ln.id_member',
1062 'fix_collect' => array(
1063 'index' => 'id_member',
1064 'process' => create_function('$members', '
1065 global $smcFunc;
1066 $smcFunc[\'db_query\'](\'\', "
1067 DELETE FROM {db_prefix}log_notify
1068 WHERE id_member IN ({array_int:members})",
1069 array(
1070 \'members\' => $members
1071 )
1072 );
1073 '),
1074 ),
1075 'messages' => array('repair_missing_notify_members', 'id_member'),
1076 ),
1077 'missing_cached_subject' => array(
1078 'substeps' => array(
1079 'step_size' => 100,
1080 'step_max' => '
1081 SELECT MAX(id_topic)
1082 FROM {db_prefix}topics'
1083 ),
1084 'check_query' => '
1085 SELECT t.id_topic, fm.subject
1086 FROM {db_prefix}topics AS t
1087 INNER JOIN {db_prefix}messages AS fm ON (fm.id_msg = t.id_first_msg)
1088 LEFT JOIN {db_prefix}log_search_subjects AS lss ON (lss.id_topic = t.id_topic)
1089 WHERE t.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
1090 AND lss.id_topic IS NULL',
1091 'fix_full_processing' => create_function('$result', '
1092 global $smcFunc;
1093
1094 $inserts = array();
1095 while ($row = $smcFunc[\'db_fetch_assoc\']($result))
1096 {
1097 foreach (text2words($row[\'subject\']) as $word)
1098 $inserts[] = array($word, $row[\'id_topic\']);
1099 if (count($inserts) > 500)
1100 {
1101 $smcFunc[\'db_insert\'](\'ignore\',
1102 "{db_prefix}log_search_subjects",
1103 array(\'word\' => \'string\', \'id_topic\' => \'int\'),
1104 $inserts,
1105 array(\'word\', \'id_topic\')
1106 );
1107 $inserts = array();
1108 }
1109
1110 }
1111
1112 if (!empty($inserts))
1113 $smcFunc[\'db_insert\'](\'ignore\',
1114 "{db_prefix}log_search_subjects",
1115 array(\'word\' => \'string\', \'id_topic\' => \'int\'),
1116 $inserts,
1117 array(\'word\', \'id_topic\')
1118 );
1119 '),
1120 'message_function' => create_function('$row', '
1121 global $txt, $context;
1122
1123 if (count(text2words($row[\'subject\'])) != 0)
1124 {
1125 $context[\'repair_errors\'][] = sprintf($txt[\'repair_missing_cached_subject\'], $row[\'id_topic\']);
1126 return true;
1127 }
1128
1129 return false;
1130 '),
1131 ),
1132 'missing_topic_for_cache' => array(
1133 'substeps' => array(
1134 'step_size' => 50,
1135 'step_max' => '
1136 SELECT MAX(id_topic)
1137 FROM {db_prefix}log_search_subjects'
1138 ),
1139 'check_query' => '
1140 SELECT lss.id_topic, lss.word
1141 FROM {db_prefix}log_search_subjects AS lss
1142 LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = lss.id_topic)
1143 WHERE lss.id_topic BETWEEN {STEP_LOW} AND {STEP_HIGH}
1144 AND t.id_topic IS NULL',
1145 'fix_collect' => array(
1146 'index' => 'id_topic',
1147 'process' => create_function('$deleteTopics', '
1148 global $smcFunc;
1149 $smcFunc[\'db_query\'](\'\', "
1150 DELETE FROM {db_prefix}log_search_subjects
1151 WHERE id_topic IN ({array_int:deleteTopics})",
1152 array(
1153 \'deleteTopics\' => $deleteTopics
1154 )
1155 );
1156 '),
1157 ),
1158 'messages' => array('repair_missing_topic_for_cache', 'word'),
1159 ),
1160 'missing_member_vote' => array(
1161 'substeps' => array(
1162 'step_size' => 500,
1163 'step_max' => '
1164 SELECT MAX(id_member)
1165 FROM {db_prefix}log_polls'
1166 ),
1167 'check_query' => '
1168 SELECT lp.id_poll, lp.id_member
1169 FROM {db_prefix}log_polls AS lp
1170 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lp.id_member)
1171 WHERE lp.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}
1172 AND lp.id_member > 0
1173 AND mem.id_member IS NULL',
1174 'fix_collect' => array(
1175 'index' => 'id_member',
1176 'process' => create_function('$members', '
1177 global $smcFunc;
1178 $smcFunc[\'db_query\'](\'\', "
1179 DELETE FROM {db_prefix}log_polls
1180 WHERE id_member IN ({array_int:members})",
1181 array(
1182 \'members\' => $members
1183 )
1184 );
1185 '),
1186 ),
1187 'messages' => array('repair_missing_log_poll_member', 'id_poll', 'id_member'),
1188 ),
1189 'missing_log_poll_vote' => array(
1190 'substeps' => array(
1191 'step_size' => 500,
1192 'step_max' => '
1193 SELECT MAX(id_poll)
1194 FROM {db_prefix}log_polls'
1195 ),
1196 'check_query' => '
1197 SELECT lp.id_poll, lp.id_member
1198 FROM {db_prefix}log_polls AS lp
1199 LEFT JOIN {db_prefix}polls AS p ON (p.id_poll = lp.id_poll)
1200 WHERE lp.id_poll BETWEEN {STEP_LOW} AND {STEP_HIGH}
1201 AND p.id_poll IS NULL',
1202 'fix_collect' => array(
1203 'index' => 'id_poll',
1204 'process' => create_function('$polls', '
1205 global $smcFunc;
1206 $smcFunc[\'db_query\'](\'\', "
1207 DELETE FROM {db_prefix}log_polls
1208 WHERE id_poll IN ({array_int:polls})",
1209 array(
1210 \'polls\' => $polls
1211 )
1212 );
1213 '),
1214 ),
1215 'messages' => array('repair_missing_log_poll_vote', 'id_member', 'id_poll'),
1216 ),
1217 'report_missing_comments' => array(
1218 'substeps' => array(
1219 'step_size' => 500,
1220 'step_max' => '
1221 SELECT MAX(id_report)
1222 FROM {db_prefix}log_reported'
1223 ),
1224 'check_query' => '
1225 SELECT lr.id_report, lr.subject
1226 FROM {db_prefix}log_reported AS lr
1227 LEFT JOIN {db_prefix}log_reported_comments AS lrc ON (lrc.id_report = lr.id_report)
1228 WHERE lr.id_report BETWEEN {STEP_LOW} AND {STEP_HIGH}
1229 AND lrc.id_report IS NULL',
1230 'fix_collect' => array(
1231 'index' => 'id_report',
1232 'process' => create_function('$reports', '
1233 global $smcFunc;
1234 $smcFunc[\'db_query\'](\'\', "
1235 DELETE FROM {db_prefix}log_reported
1236 WHERE id_report IN ({array_int:reports})",
1237 array(
1238 \'reports\' => $reports
1239 )
1240 );
1241 '),
1242 ),
1243 'messages' => array('repair_report_missing_comments', 'id_report', 'subject'),
1244 ),
1245 'comments_missing_report' => array(
1246 'substeps' => array(
1247 'step_size' => 200,
1248 'step_max' => '
1249 SELECT MAX(id_report)
1250 FROM {db_prefix}log_reported_comments'
1251 ),
1252 'check_query' => '
1253 SELECT lrc.id_report, lrc.membername
1254 FROM {db_prefix}log_reported_comments AS lrc
1255 LEFT JOIN {db_prefix}log_reported AS lr ON (lr.id_report = lrc.id_report)
1256 WHERE lrc.id_report BETWEEN {STEP_LOW} AND {STEP_HIGH}
1257 AND lr.id_report IS NULL',
1258 'fix_collect' => array(
1259 'index' => 'id_report',
1260 'process' => create_function('$reports', '
1261 global $smcFunc;
1262 $smcFunc[\'db_query\'](\'\', "
1263 DELETE FROM {db_prefix}log_reported_comments
1264 WHERE id_report IN ({array_int:reports})",
1265 array(
1266 \'reports\' => $reports
1267 )
1268 );
1269 '),
1270 ),
1271 'messages' => array('repair_comments_missing_report', 'id_report', 'membername'),
1272 ),
1273 'group_request_missing_member' => array(
1274 'substeps' => array(
1275 'step_size' => 200,
1276 'step_max' => '
1277 SELECT MAX(id_member)
1278 FROM {db_prefix}log_group_requests'
1279 ),
1280 'check_query' => '
1281 SELECT lgr.id_member
1282 FROM {db_prefix}log_group_requests AS lgr
1283 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lgr.id_member)
1284 WHERE lgr.id_member BETWEEN {STEP_LOW} AND {STEP_HIGH}
1285 AND mem.id_member IS NULL
1286 GROUP BY lgr.id_member',
1287 'fix_collect' => array(
1288 'index' => 'id_member',
1289 'process' => create_function('$members', '
1290 global $smcFunc;
1291 $smcFunc[\'db_query\'](\'\', "
1292 DELETE FROM {db_prefix}log_group_requests
1293 WHERE id_member IN ({array_int:members})",
1294 array(
1295 \'members\' => $members
1296 )
1297 );
1298 '),
1299 ),
1300 'messages' => array('repair_group_request_missing_member', 'id_member'),
1301 ),
1302 'group_request_missing_group' => array(
1303 'substeps' => array(
1304 'step_size' => 200,
1305 'step_max' => '
1306 SELECT MAX(id_group)
1307 FROM {db_prefix}log_group_requests'
1308 ),
1309 'check_query' => '
1310 SELECT lgr.id_group
1311 FROM {db_prefix}log_group_requests AS lgr
1312 LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = lgr.id_group)
1313 WHERE lgr.id_group BETWEEN {STEP_LOW} AND {STEP_HIGH}
1314 AND mg.id_group IS NULL
1315 GROUP BY lgr.id_group',
1316 'fix_collect' => array(
1317 'index' => 'id_group',
1318 'process' => create_function('$groups', '
1319 global $smcFunc;
1320 $smcFunc[\'db_query\'](\'\', \'
1321 DELETE FROM {db_prefix}log_group_requests
1322 WHERE id_group IN ({array_int:groups})\',
1323 array(
1324 \'groups\' => $groups
1325 )
1326 );
1327 '),
1328 ),
1329 'messages' => array('repair_group_request_missing_group', 'id_group'),
1330 ),
1331 );
1332 }
1333
1334 function findForumErrors($do_fix = false)
1335 {
1336 global $context, $txt, $smcFunc, $errorTests, $db_cache, $db_temp_cache;
1337
1338 // This may take some time...
1339 @set_time_limit(600);
1340
1341 $to_fix = !empty($_SESSION['repairboards_to_fix']) ? $_SESSION['repairboards_to_fix'] : array();
1342 $context['repair_errors'] = isset($_SESSION['repairboards_to_fix2']) ? $_SESSION['repairboards_to_fix2'] : array();
1343
1344 $_GET['step'] = empty($_GET['step']) ? 0 : (int) $_GET['step'];
1345 $_GET['substep'] = empty($_GET['substep']) ? 0 : (int) $_GET['substep'];
1346
1347 // Don't allow the cache to get too full.
1348 $db_temp_cache = $db_cache;
1349 $db_cache = '';
1350
1351 $context['total_steps'] = count($errorTests);
1352
1353 // For all the defined error types do the necessary tests.
1354 $current_step = -1;
1355 $total_queries = 0;
1356 foreach ($errorTests as $error_type => $test)
1357 {
1358 $current_step++;
1359
1360 // Already done this?
1361 if ($_GET['step'] > $current_step)
1362 continue;
1363
1364 // If we're fixing it but it ain't broke why try?
1365 if ($do_fix && !in_array($error_type, $to_fix))
1366 {
1367 $_GET['step']++;
1368 continue;
1369 }
1370
1371 // Has it got substeps?
1372 if (isset($test['substeps']))
1373 {
1374 $step_size = isset($test['substeps']['step_size']) ? $test['substeps']['step_size'] : 100;
1375 $request = $smcFunc['db_query']('',
1376 $test['substeps']['step_max'],
1377 array(
1378 )
1379 );
1380 list ($step_max) = $smcFunc['db_fetch_row']($request);
1381
1382 $total_queries++;
1383 $smcFunc['db_free_result']($request);
1384 }
1385
1386 // We in theory keep doing this... the substeps.
1387 $done = false;
1388 while (!$done)
1389 {
1390 // Make sure there's at least one ID to test.
1391 if (isset($test['substeps']) && empty($step_max))
1392 break;
1393
1394 // What is the testing query (Changes if we are testing or fixing)
1395 if (!$do_fix)
1396 $test_query = 'check_query';
1397 else
1398 $test_query = isset($test['fix_query']) ? 'fix_query' : 'check_query';
1399
1400 // Do the test...
1401 $request = $smcFunc['db_query']('',
1402 isset($test['substeps']) ? strtr($test[$test_query], array('{STEP_LOW}' => $_GET['substep'], '{STEP_HIGH}' => $_GET['substep'] + $step_size - 1)) : $test[$test_query],
1403 array(
1404 )
1405 );
1406 $needs_fix = false;
1407
1408 // Does it need a fix?
1409 if (!empty($test['check_type']) && $test['check_type'] == 'count')
1410 list ($needs_fix) = $smcFunc['db_fetch_row']($request);
1411 else
1412 $needs_fix = $smcFunc['db_num_rows']($request);
1413
1414 $total_queries++;
1415
1416 if ($needs_fix)
1417 {
1418 // What about a message to the user?
1419 if (!$do_fix)
1420 {
1421 // Assume need to fix.
1422 $found_errors = true;
1423
1424 if (isset($test['message']))
1425 $context['repair_errors'][] = $txt[$test['message']];
1426
1427 // One per row!
1428 elseif (isset($test['messages']))
1429 {
1430 while ($row = $smcFunc['db_fetch_assoc']($request))
1431 {
1432 $variables = $test['messages'];
1433 foreach ($variables as $k => $v)
1434 {
1435 if ($k == 0 && isset($txt[$v]))
1436 $variables[$k] = $txt[$v];
1437 elseif ($k > 0 && isset($row[$v]))
1438 $variables[$k] = $row[$v];
1439 }
1440 $context['repair_errors'][] = call_user_func_array('sprintf', $variables);
1441 }
1442 }
1443
1444 // A function to process?
1445 elseif (isset($test['message_function']))
1446 {
1447 // Find out if there are actually errors.
1448 $found_errors = false;
1449 while ($row = $smcFunc['db_fetch_assoc']($request))
1450 $found_errors |= $test['message_function']($row);
1451 }
1452
1453 // Actually have something to fix?
1454 if ($found_errors)
1455 $to_fix[] = $error_type;
1456 }
1457
1458 // We want to fix, we need to fix - so work out what exactly to do!
1459 else
1460 {
1461 // Are we simply getting a collection of ids?
1462 if (isset($test['fix_collect']))
1463 {
1464 $ids = array();
1465 while ($row = $smcFunc['db_fetch_assoc']($request))
1466 $ids[] = $row[$test['fix_collect']['index']];
1467 if (!empty($ids))
1468 {
1469 // Fix it!
1470 $test['fix_collect']['process']($ids);
1471 }
1472 }
1473
1474 // Simply executing a fix it query?
1475 elseif (isset($test['fix_it_query']))
1476 $smcFunc['db_query']('',
1477 $test['fix_it_query'],
1478 array(
1479 )
1480 );
1481
1482 // Do we have some processing to do?
1483 elseif (isset($test['fix_processing']))
1484 {
1485 while ($row = $smcFunc['db_fetch_assoc']($request))
1486 $test['fix_processing']($row);
1487 }
1488
1489 // What about the full set of processing?
1490 elseif (isset($test['fix_full_processing']))
1491 $test['fix_full_processing']($request);
1492
1493 // Do we have other things we need to fix as a result?
1494 if (!empty($test['force_fix']))
1495 {
1496 foreach ($test['force_fix'] as $item)
1497 if (!in_array($item, $to_fix))
1498 $to_fix[] = $item;
1499 }
1500 }
1501 }
1502
1503 // Free the result.
1504 $smcFunc['db_free_result']($request);
1505 // Keep memory down.
1506 $db_cache = '';
1507
1508 // Are we done yet?
1509 if (isset($test['substeps']))
1510 {
1511 $_GET['substep'] += $step_size;
1512 // Not done?
1513 if ($_GET['substep'] <= $step_max)
1514 {
1515 pauseRepairProcess($to_fix, $error_type, $step_max);
1516 }
1517 else
1518 $done = true;
1519 }
1520 else
1521 $done = true;
1522
1523 // Don't allow more than 1000 queries at a time.
1524 if ($total_queries >= 1000)
1525 pauseRepairProcess($to_fix, $error_type, $step_max, true);
1526 }
1527
1528 // Keep going.
1529 $_GET['step']++;
1530 $_GET['substep'] = 0;
1531
1532 $to_fix = array_unique($to_fix);
1533
1534 // If we're doing fixes and this needed a fix and we're all done then don't do it again.
1535 if ($do_fix)
1536 {
1537 $key = array_search($error_type, $to_fix);
1538 if ($key !== false && isset($to_fix[$key]))
1539 unset($to_fix[$key]);
1540 }
1541
1542 // Are we done?
1543 pauseRepairProcess($to_fix, $error_type);
1544 }
1545
1546 // Restore the cache.
1547 $db_cache = $db_temp_cache;
1548
1549 return $to_fix;
1550 }
1551
1552 // Create a salvage area for repair purposes.
1553 function createSalvageArea()
1554 {
1555 global $txt, $language, $salvageBoardID, $salvageCatID, $smcFunc;
1556 static $createOnce = false;
1557
1558 // Have we already created it?
1559 if ($createOnce)
1560 return;
1561 else
1562 $createOnce = true;
1563
1564 // Back to the forum's default language.
1565 loadLanguage('Admin', $language);
1566
1567 // Check to see if a 'Salvage Category' exists, if not => insert one.
1568 $result = $smcFunc['db_query']('', '
1569 SELECT id_cat
1570 FROM {db_prefix}categories
1571 WHERE name = {string:cat_name}
1572 LIMIT 1',
1573 array(
1574 'cat_name' => $txt['salvaged_category_name'],
1575 )
1576 );
1577 if ($smcFunc['db_num_rows']($result) != 0)
1578 list ($salvageCatID) = $smcFunc['db_fetch_row']($result);
1579 $smcFunc['db_free_result']($result);
1580
1581 if (empty($salveageCatID))
1582 {
1583 $smcFunc['db_insert']('',
1584 '{db_prefix}categories',
1585 array('name' => 'string-255', 'cat_order' => 'int'),
1586 array($txt['salvaged_category_name'], -1),
1587 array('id_cat')
1588 );
1589
1590 if ($smcFunc['db_affected_rows']() <= 0)
1591 {
1592 loadLanguage('Admin');
1593 fatal_lang_error('salvaged_category_error', false);
1594 }
1595
1596 $salvageCatID = $smcFunc['db_insert_id']('{db_prefix}categories', 'id_cat');
1597 }
1598
1599 // Check to see if a 'Salvage Board' exists, if not => insert one.
1600 $result = $smcFunc['db_query']('', '
1601 SELECT id_board
1602 FROM {db_prefix}boards
1603 WHERE id_cat = {int:id_cat}
1604 AND name = {string:board_name}
1605 LIMIT 1',
1606 array(
1607 'id_cat' => $salvageCatID,
1608 'board_name' => $txt['salvaged_board_name'],
1609 )
1610 );
1611 if ($smcFunc['db_num_rows']($result) != 0)
1612 list ($salvageBoardID) = $smcFunc['db_fetch_row']($result);
1613 $smcFunc['db_free_result']($result);
1614
1615 if (empty($salvageBoardID))
1616 {
1617 $smcFunc['db_insert']('',
1618 '{db_prefix}boards',
1619 array('name' => 'string-255', 'description' => 'string-255', 'id_cat' => 'int', 'member_groups' => 'string', 'board_order' => 'int', 'redirect' => 'string'),
1620 array($txt['salvaged_board_name'], $txt['salvaged_board_description'], $salvageCatID, '1', -1, ''),
1621 array('id_board')
1622 );
1623
1624 if ($smcFunc['db_affected_rows']() <= 0)
1625 {
1626 loadLanguage('Admin');
1627 fatal_lang_error('salvaged_board_error', false);
1628 }
1629
1630 $salvageBoardID = $smcFunc['db_insert_id']('{db_prefix}boards', 'id_board');
1631 }
1632
1633 $smcFunc['db_query']('alter_table_boards', '
1634 ALTER TABLE {db_prefix}boards
1635 ORDER BY board_order',
1636 array(
1637 )
1638 );
1639
1640 // Restore the user's language.
1641 loadLanguage('Admin');
1642 }
1643
1644 ?>