Completed
Pull Request — patch_1-1-4 (#3210)
by Emanuele
12:56
created

Maintenance.subs.php ➔ updateZeroPostMembers()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
nc 3
nop 0
dl 0
loc 53
rs 9.0254
c 0
b 0
f 0
ccs 0
cts 44
cp 0
crap 20

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Forum maintenance support functions. Important stuff.
5
 *
6
 * @name      ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
9
 *
10
 * This file contains code covered by:
11
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
12
 * license:  	BSD, See included LICENSE.TXT for terms and conditions.
13
 *
14
 * @version 1.1
15
 *
16
 */
17
/**
18
 * Counts the total number of messages
19
 *
20
 * @package Maintenance
21
 * @return int
22
 */
23
function countMessages()
24
{
25
	$db = database();
26
27
	$request = $db->query('', '
28
		SELECT COUNT(*)
29
		FROM {db_prefix}messages',
30
		array()
31
	);
32
	list ($messages) = $db->fetch_row($request);
33
	$db->free_result($request);
34
35
	return $messages;
36
}
37
38
/**
39
 * Flushes all log tables
40
 *
41
 * @package Maintenance
42
 */
43
function flushLogTables()
44
{
45
	$db = database();
46
47
	$db->query('', '
48
		DELETE FROM {db_prefix}log_online');
49
50
	// Dump the banning logs.
51
	$db->query('', '
52
		DELETE FROM {db_prefix}log_banned');
53
54
	// Start id_error back at 0 and dump the error log.
55
	$db->query('truncate_table', '
56
		TRUNCATE {db_prefix}log_errors');
57
58
	// Clear out the spam log.
59
	$db->query('', '
60
		DELETE FROM {db_prefix}log_floodcontrol');
61
62
	// Clear out the karma actions.
63
	$db->query('', '
64
		DELETE FROM {db_prefix}log_karma');
65
66
	// Last but not least, the search logs!
67
	$db->query('truncate_table', '
68
		TRUNCATE {db_prefix}log_search_topics');
69
70
	$db->query('truncate_table', '
71
		TRUNCATE {db_prefix}log_search_messages');
72
73
	$db->query('truncate_table', '
74
		TRUNCATE {db_prefix}log_search_results');
75
}
76
77
/**
78
 * Gets the table columns from the messages table, just a wrapper function
79
 *
80
 * @package Maintenance
81
 * @return array
82
 */
83
function getMessageTableColumns()
84
{
85
	$table = db_table();
86
	$colData = $table->db_list_columns('{db_prefix}messages', true);
87
88
	return $colData;
89
}
90
91
/**
92
 * Retrieve information about the body column of the messages table
93
 * Used in action_database
94
 *
95
 * @package Maintenance
96
 */
97
function fetchBodyType()
98
{
99
	$table = db_table();
100
101
	$colData = $table->db_list_columns('{db_prefix}messages', true);
102
	foreach ($colData as $column)
103
		if ($column['name'] == 'body')
104
			$body_type = $column['type'];
105
106
	return $body_type;
0 ignored issues
show
Bug introduced by
The variable $body_type does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
107
}
108
109
/**
110
 * Resizes the body column from the messages table
111
 *
112
 * @package Maintenance
113
 * @param string $type
114
 */
115
function resizeMessageTableBody($type)
116
{
117
	$table = db_table();
118
	$table->db_change_column('{db_prefix}messages', 'body', array('type' => $type));
119
}
120
121
/**
122
 * Detects messages, which exceed the max message size
123
 *
124
 * @package Maintenance
125
 * @param int $start The item to start with (for pagination purposes)
126
 * @param int $increment
127
 */
128
function detectExceedingMessages($start, $increment)
129
{
130
	$db = database();
131
132
	return $db->fetchQueryCallback('
133
		SELECT /*!40001 SQL_NO_CACHE */ id_msg
134
		FROM {db_prefix}messages
135
		WHERE id_msg BETWEEN {int:start} AND {int:start} + {int:increment}
136
			AND LENGTH(body) > 65535',
137
		array(
138
			'start' => $start,
139
			'increment' => $increment - 1,
140
		),
141
		function ($row)
142
		{
143
			return $row['id_msg'];
144
		}
145
	);
146
}
147
148
/**
149
 * loads messages, which exceed the length that will fit in the col field
150
 *
151
 * - Used by maintenance when convert the column "body" of the table from TEXT
152
 * to MEDIUMTEXT and vice versa.
153
 *
154
 * @package Maintenance
155
 * @param int[] $msg
156
 * @return array
157
 */
158
function getExceedingMessages($msg)
159
{
160
	global $scripturl;
161
162
	$db = database();
163
164
	return $db->fetchQueryCallback('
165
		SELECT id_msg, id_topic, subject
166
		FROM {db_prefix}messages
167
		WHERE id_msg IN ({array_int:messages})',
168
		array(
169
			'messages' => $msg,
170
		),
171
		function ($row) use ($scripturl)
172
		{
173
			return '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] . '">' . $row['subject'] . '</a>';
174
		}
175
	);
176
}
177
178
/**
179
 * Lists all the tables from our ElkArte installation.
180
 *
181
 * - Additional tables from addons are also included.
182
 *
183
 * @package Maintenance
184
 * @return array
185
 */
186
function getElkTables()
187
{
188
	global $db_prefix;
189
190
	$db = database();
191
192
	$tables = array();
193
194
	// Only optimize the tables related to this installation, not all the tables in the db
195
	$real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix;
196
197
	// Get a list of tables, as well as how many there are.
198
	$temp_tables = $db->db_list_tables(false, $real_prefix . '%');
199
	foreach ($temp_tables as $table)
200
			$tables[] = array('table_name' => $table);
201
202
	return $tables;
203
}
204
205
/**
206
 * Wrapper function for db_optimize_table
207
 *
208
 * @package Maintenance
209
 * @param string $tablename
210
 */
211
function optimizeTable($tablename)
212
{
213
	$db_table = db_table();
214
215
	return $db_table->optimize($tablename);
216
}
217
218
/**
219
 * Gets the last topics id.
220
 *
221
 * @package Maintenance
222
 * @return int
223
 */
224
function getMaxTopicID()
225
{
226
	$db = database();
227
228
	$request = $db->query('', '
229
		SELECT MAX(id_topic)
230
		FROM {db_prefix}topics',
231
		array(
232
		)
233
	);
234
	list ($id_topic) = $db->fetch_row($request);
235
	$db->free_result($request);
236
237
	return $id_topic;
238
}
239
240
/**
241
 * Recounts all approved messages
242
 *
243
 * @package Maintenance
244
 * @param int $start The item to start with (for pagination purposes)
245
 * @param int $increment
246
 */
247 View Code Duplication
function recountApprovedMessages($start, $increment)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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.

Loading history...
248
{
249
	$db = database();
250
251
	// Recount approved messages
252
	$db->fetchQueryCallback('
253
		SELECT /*!40001 SQL_NO_CACHE */ t.id_topic, MAX(t.num_replies) AS num_replies,
254
			CASE WHEN COUNT(ma.id_msg) >= 1 THEN COUNT(ma.id_msg) - 1 ELSE 0 END AS real_num_replies
255
		FROM {db_prefix}topics AS t
256
			LEFT JOIN {db_prefix}messages AS ma ON (ma.id_topic = t.id_topic AND ma.approved = {int:is_approved})
257
		WHERE t.id_topic > {int:start}
258
			AND t.id_topic <= {int:max_id}
259
		GROUP BY t.id_topic
260
		HAVING CASE WHEN COUNT(ma.id_msg) >= 1 THEN COUNT(ma.id_msg) - 1 ELSE 0 END != MAX(t.num_replies)',
261
		array(
262
			'is_approved' => 1,
263
			'start' => $start,
264
			'max_id' => $start + $increment,
265
		),
266
		function ($row)
267
		{
268
			setTopicAttribute($row['id_topic'], array('num_replies' => $row['real_num_replies']));
269
		}
270
	);
271
}
272
273
/**
274
 * Recounts all unapproved messages
275
 *
276
 * @package Maintenance
277
 * @param int $start The item to start with (for pagination purposes)
278
 * @param int $increment
279
 */
280 View Code Duplication
function recountUnapprovedMessages($start, $increment)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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.

Loading history...
281
{
282
	$db = database();
283
284
	// Recount unapproved messages
285
	$db->fetchQueryCallback('
286
		SELECT /*!40001 SQL_NO_CACHE */ t.id_topic, MAX(t.unapproved_posts) AS unapproved_posts,
287
			COUNT(mu.id_msg) AS real_unapproved_posts
288
		FROM {db_prefix}topics AS t
289
			LEFT JOIN {db_prefix}messages AS mu ON (mu.id_topic = t.id_topic AND mu.approved = {int:not_approved})
290
		WHERE t.id_topic > {int:start}
291
			AND t.id_topic <= {int:max_id}
292
		GROUP BY t.id_topic
293
		HAVING COUNT(mu.id_msg) != MAX(t.unapproved_posts)',
294
		array(
295
			'not_approved' => 0,
296
			'start' => $start,
297
			'max_id' => $start + $increment,
298
		),
299
		function ($row)
300
		{
301
			setTopicAttribute($row['id_topic'], array('unapproved_posts' => $row['real_unapproved_posts']));
302
		}
303
	);
304
}
305
306
/**
307
 * Reset the boards table's counter for posts, topics, unapproved posts and
308
 * unapproved topics
309
 *
310
 * - Allowed parameters: num_posts, num_topics, unapproved_posts, unapproved_topics
311
 *
312
 * @package Maintenance
313
 * @param string $column
314
 */
315
function resetBoardsCounter($column)
316
{
317
	$db = database();
318
319
	$allowed_columns = array('num_posts', 'num_topics', 'unapproved_posts', 'unapproved_topics');
320
321
	if (!in_array($column, $allowed_columns))
322
			return false;
323
324
	$db->query('', '
325
		UPDATE {db_prefix}boards
326
		SET ' . $column . ' = {int:counter}
327
		WHERE redirect = {string:redirect}',
328
		array(
329
			'counter' => 0,
330
			'redirect' => '',
331
		)
332
	);
333
}
334
335
/**
336
 * Recalculates the boards table's counter
337
 *
338
 * @package Maintenance
339
 * @param string $type - can be 'posts', 'topic', 'unapproved_posts', 'unapproved_topics'
340
 * @param int $start The item to start with (for pagination purposes)
341
 * @param int $increment
342
 */
343
function updateBoardsCounter($type, $start, $increment)
344
{
345
	$db = database();
346
347
	switch ($type)
348
	{
349 View Code Duplication
		case 'posts':
350
			$request = $db->query('', '
351
				SELECT /*!40001 SQL_NO_CACHE */ m.id_board, COUNT(*) AS real_num_posts
352
				FROM {db_prefix}messages AS m
353
				WHERE m.id_topic > {int:id_topic_min}
354
					AND m.id_topic <= {int:id_topic_max}
355
					AND m.approved = {int:is_approved}
356
				GROUP BY m.id_board',
357
				array(
358
					'id_topic_min' => $start,
359
					'id_topic_max' => $start + $increment,
360
					'is_approved' => 1,
361
				)
362
			);
363
			while ($row = $db->fetch_assoc($request))
364
			{
365
				$db->query('', '
366
					UPDATE {db_prefix}boards
367
					SET num_posts = num_posts + {int:real_num_posts}
368
					WHERE id_board = {int:id_board}',
369
					array(
370
						'id_board' => $row['id_board'],
371
						'real_num_posts' => $row['real_num_posts'],
372
					)
373
				);
374
			}
375
			$db->free_result($request);
376
			break;
377
378 View Code Duplication
		case 'topics':
379
			$request = $db->query('', '
380
				SELECT /*!40001 SQL_NO_CACHE */ t.id_board, COUNT(*) AS real_num_topics
381
				FROM {db_prefix}topics AS t
382
				WHERE t.approved = {int:is_approved}
383
					AND t.id_topic > {int:id_topic_min}
384
					AND t.id_topic <= {int:id_topic_max}
385
				GROUP BY t.id_board',
386
				array(
387
					'is_approved' => 1,
388
					'id_topic_min' => $start,
389
					'id_topic_max' => $start + $increment,
390
				)
391
			);
392
			while ($row = $db->fetch_assoc($request))
393
			{
394
				$db->query('', '
395
					UPDATE {db_prefix}boards
396
					SET num_topics = num_topics + {int:real_num_topics}
397
					WHERE id_board = {int:id_board}',
398
					array(
399
						'id_board' => $row['id_board'],
400
						'real_num_topics' => $row['real_num_topics'],
401
					)
402
				);
403
			}
404
			$db->free_result($request);
405
			break;
406
407 View Code Duplication
		case 'unapproved_posts':
408
			$request = $db->query('', '
409
				SELECT /*!40001 SQL_NO_CACHE */ m.id_board, COUNT(*) AS real_unapproved_posts
410
				FROM {db_prefix}messages AS m
411
				WHERE m.id_topic > {int:id_topic_min}
412
					AND m.id_topic <= {int:id_topic_max}
413
					AND m.approved = {int:is_approved}
414
				GROUP BY m.id_board',
415
				array(
416
					'id_topic_min' => $start,
417
					'id_topic_max' => $start + $increment,
418
					'is_approved' => 0,
419
				)
420
			);
421
			while ($row = $db->fetch_assoc($request))
422
			{
423
				$db->query('', '
424
					UPDATE {db_prefix}boards
425
					SET unapproved_posts = unapproved_posts + {int:unapproved_posts}
426
					WHERE id_board = {int:id_board}',
427
					array(
428
						'id_board' => $row['id_board'],
429
						'unapproved_posts' => $row['real_unapproved_posts'],
430
					)
431
				);
432
			}
433
			$db->free_result($request);
434
			break;
435
436 View Code Duplication
		case 'unapproved_topics':
437
			$request = $db->query('', '
438
				SELECT /*!40001 SQL_NO_CACHE */ t.id_board, COUNT(*) AS real_unapproved_topics
439
				FROM {db_prefix}topics AS t
440
				WHERE t.approved = {int:is_approved}
441
					AND t.id_topic > {int:id_topic_min}
442
					AND t.id_topic <= {int:id_topic_max}
443
				GROUP BY t.id_board',
444
				array(
445
					'is_approved' => 0,
446
					'id_topic_min' => $start,
447
					'id_topic_max' => $start + $increment,
448
				)
449
			);
450
			while ($row = $db->fetch_assoc($request))
451
			{
452
				$db->query('', '
453
					UPDATE {db_prefix}boards
454
					SET unapproved_topics = unapproved_topics + {int:real_unapproved_topics}
455
					WHERE id_board = {int:id_board}',
456
					array(
457
						'id_board' => $row['id_board'],
458
						'real_unapproved_topics' => $row['real_unapproved_topics'],
459
					)
460
				);
461
			}
462
			$db->free_result($request);
463
			break;
464
465
		default:
466
			trigger_error('updateBoardsCounter(): Invalid counter type \'' . $type . '\'', E_USER_NOTICE);
467
	}
468
}
469
470
/**
471
 * Update the personal messages counter
472
 *
473
 * @package Maintenance
474
 */
475
function updatePersonalMessagesCounter()
476
{
477
	$db = database();
478
479
	require_once(SUBSDIR . '/Members.subs.php');
480
481
	$db->fetchQueryCallback('
482
		SELECT /*!40001 SQL_NO_CACHE */ mem.id_member, COUNT(pmr.id_pm) AS real_num,
483
			MAX(mem.personal_messages) AS personal_messages
484
		FROM {db_prefix}members AS mem
485
			LEFT JOIN {db_prefix}pm_recipients AS pmr ON (mem.id_member = pmr.id_member AND pmr.deleted = {int:is_not_deleted})
486
		GROUP BY mem.id_member
487
		HAVING COUNT(pmr.id_pm) != MAX(mem.personal_messages)',
488
		array(
489
			'is_not_deleted' => 0,
490
		),
491
		function ($row)
492
		{
493
			updateMemberData($row['id_member'], array('personal_messages' => $row['real_num']));
494
		}
495
	);
496
497
	$db->fetchQueryCallback('
498
		SELECT /*!40001 SQL_NO_CACHE */ mem.id_member, COUNT(pmr.id_pm) AS real_num,
499
			MAX(mem.unread_messages) AS unread_messages
500
		FROM {db_prefix}members AS mem
501
			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})
502
		GROUP BY mem.id_member
503
		HAVING COUNT(pmr.id_pm) != MAX(mem.unread_messages)',
504
		array(
505
			'is_not_deleted' => 0,
506
			'is_not_read' => 0,
507
		),
508
		function ($row)
509
		{
510
			updateMemberData($row['id_member'], array('unread_messages' => $row['real_num']));
511
		}
512
	);
513
}
514
515
/**
516
 * Fixes the column id_board from the messages table.
517
 *
518
 * @package Maintenance
519
 * @param int $start The item to start with (for pagination purposes)
520
 * @param int $increment
521
 */
522
function updateMessagesBoardID($start, $increment)
523
{
524
	$db = database();
525
526
	$request = $db->query('', '
527
		SELECT /*!40001 SQL_NO_CACHE */ t.id_board, m.id_msg
528
		FROM {db_prefix}messages AS m
529
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic AND t.id_board != m.id_board)
530
		WHERE m.id_msg > {int:id_msg_min}
531
			AND m.id_msg <= {int:id_msg_max}',
532
		array(
533
			'id_msg_min' => $start,
534
			'id_msg_max' => $start + $increment,
535
		)
536
	);
537
	$boards = array();
538
	while ($row = $db->fetch_assoc($request))
539
		$boards[$row['id_board']][] = $row['id_msg'];
540
	$db->free_result($request);
541
542
	foreach ($boards as $board_id => $messages)
543
		$db->query('', '
544
			UPDATE {db_prefix}messages
545
			SET id_board = {int:id_board}
546
			WHERE id_msg IN ({array_int:id_msg_array})',
547
			array(
548
				'id_msg_array' => $messages,
549
				'id_board' => $board_id,
550
			)
551
		);
552
}
553
554
/**
555
 * Updates the latest message of each board.
556
 *
557
 * @package Maintenance
558
 */
559
function updateBoardsLastMessage()
560
{
561
	$db = database();
562
563
	// Update the latest message of each board.
564
	$request = $db->query('', '
565
		SELECT m.id_board, MAX(m.id_msg) AS local_last_msg
566
		FROM {db_prefix}messages AS m
567
		WHERE m.approved = {int:is_approved}
568
		GROUP BY m.id_board',
569
		array(
570
			'is_approved' => 1,
571
		)
572
	);
573
	$realBoardCounts = array();
574
	while ($row = $db->fetch_assoc($request))
575
		$realBoardCounts[$row['id_board']] = $row['local_last_msg'];
576
	$db->free_result($request);
577
578
	$request = $db->query('', '
579
		SELECT /*!40001 SQL_NO_CACHE */ id_board, id_parent, id_last_msg, child_level, id_msg_updated
580
		FROM {db_prefix}boards',
581
		array(
582
		)
583
	);
584
	$resort_me = array();
585 View Code Duplication
	while ($row = $db->fetch_assoc($request))
586
	{
587
		$row['local_last_msg'] = isset($realBoardCounts[$row['id_board']]) ? $realBoardCounts[$row['id_board']] : 0;
588
		$resort_me[$row['child_level']][] = $row;
589
	}
590
	$db->free_result($request);
591
592
	krsort($resort_me);
593
594
	$lastModifiedMsg = array();
595
	foreach ($resort_me as $rows)
596
		foreach ($rows as $row)
597
		{
598
			// The latest message is the latest of the current board and its children.
599
			if (isset($lastModifiedMsg[$row['id_board']]))
600
				$curLastModifiedMsg = max($row['local_last_msg'], $lastModifiedMsg[$row['id_board']]);
601
			else
602
				$curLastModifiedMsg = $row['local_last_msg'];
603
				// If what is and what should be the latest message differ, an update is necessary.
604
			if ($row['local_last_msg'] != $row['id_last_msg'] || $curLastModifiedMsg != $row['id_msg_updated'])
605
				$db->query('', '
606
					UPDATE {db_prefix}boards
607
					SET id_last_msg = {int:id_last_msg}, id_msg_updated = {int:id_msg_updated}
608
					WHERE id_board = {int:id_board}',
609
					array(
610
						'id_last_msg' => $row['local_last_msg'],
611
						'id_msg_updated' => $curLastModifiedMsg,
612
						'id_board' => $row['id_board'],
613
					)
614
				);
615
616
			// Parent boards inherit the latest modified message of their children.
617
			if (isset($lastModifiedMsg[$row['id_parent']]))
618
				$lastModifiedMsg[$row['id_parent']] = max($row['local_last_msg'], $lastModifiedMsg[$row['id_parent']]);
619
			else
620
				$lastModifiedMsg[$row['id_parent']] = $row['local_last_msg'];
621
		}
622
}
623
624
/**
625
 * Counts topics from a given board.
626
 *
627
 * @package Maintenance
628
 * @param int $id_board
629
 * @return int
630
 */
631
function countTopicsFromBoard($id_board)
632
{
633
	$db = database();
634
635
	$request = $db->query('', '
636
		SELECT COUNT(*)
637
		FROM {db_prefix}topics
638
		WHERE id_board = {int:id_board}',
639
		array(
640
			'id_board' => $id_board,
641
		)
642
	);
643
	list ($total_topics) = $db->fetch_row($request);
644
	$db->free_result($request);
645
646
	return $total_topics;
647
}
648
649
/**
650
 * Gets a list of the next 10 topics which should be moved to a different board.
651
 *
652
 * @package Maintenance
653
 * @param int $id_board
654
 *
655
 * @return int[]
656
 */
657
function getTopicsToMove($id_board)
658
{
659
	$db = database();
660
661
	// Lets get the topics.
662
	return $db->fetchQueryCallback('
663
		SELECT id_topic
664
		FROM {db_prefix}topics
665
		WHERE id_board = {int:id_board}
666
		LIMIT 10',
667
		array(
668
			'id_board' => $id_board,
669
		),
670
		function ($row)
671
		{
672
			return $row['id_topic'];
673
		}
674
	);
675
}
676
677
/**
678
 * Counts members with posts > 0, we name them contributors
679
 *
680
 * @package Maintenance
681
 * @return int
682
 */
683
function countContributors()
684
{
685
	$db = database();
686
687
	$request = $db->query('', '
688
		SELECT COUNT(DISTINCT m.id_member)
689
		FROM ({db_prefix}messages AS m, {db_prefix}boards AS b)
690
		WHERE m.id_member != 0
691
			AND b.count_posts = 0
692
			AND m.id_board = b.id_board',
693
		array(
694
		)
695
	);
696
697
	// save it so we don't do this again for this task
698
	list ($total_members) = $db->fetch_row($request);
699
	$db->free_result($request);
700
701
	return $total_members;
702
}
703
704
/**
705
 * Recount the members posts.
706
 *
707
 * @package Maintenance
708
 * @param int $start The item to start with (for pagination purposes)
709
 * @param int $increment
710
 * @return int
711
 */
712
function updateMembersPostCount($start, $increment)
713
{
714
	global $modSettings;
715
716
	$db = database();
717
718
	$request = $db->query('', '
719
		SELECT /*!40001 SQL_NO_CACHE */ m.id_member, COUNT(m.id_member) AS posts
720
		FROM {db_prefix}messages AS m
721
			INNER JOIN {db_prefix}boards AS b ON (m.id_board = b.id_board)
722
		WHERE m.id_member != {int:zero}
723
			AND b.count_posts = {int:zero}' . (!empty($modSettings['recycle_enable']) ? '
724
			AND b.id_board != {int:recycle}' : '') . '
725
		GROUP BY m.id_member
726
		LIMIT {int:start}, {int:number}',
727
		array(
728
			'start' => $start,
729
			'number' => $increment,
730
			'recycle' => $modSettings['recycle_board'],
731
			'zero' => 0,
732
		)
733
	);
734
	$total_rows = $db->num_rows($request);
735
736
	// Update the post count for this group
737
	require_once(SUBSDIR . '/Members.subs.php');
738
	while ($row = $db->fetch_assoc($request))
739
		updateMemberData($row['id_member'], array('posts' => $row['posts']));
740
	$db->free_result($request);
741
742
	return $total_rows;
743
}
744
745
/**
746
 * Used to find members who have a post count >0 that should not.
747
 *
748
 * - Made more difficult since we don't yet support sub-selects on joins so we
749
 * place all members who have posts in the message table in a temp table
750
 *
751
 * @package Maintenance
752
 */
753
function updateZeroPostMembers()
754
{
755
	global $modSettings;
756
757
	$db = database();
758
759
	$db->skip_next_error();
760
	$createTemporary = $db->query('', '
761
		CREATE TEMPORARY TABLE {db_prefix}tmp_maint_recountposts (
762
			id_member mediumint(8) unsigned NOT NULL default {string:string_zero},
763
			PRIMARY KEY (id_member)
764
		)
765
		SELECT m.id_member
766
		FROM {db_prefix}messages AS m
767
			INNER JOIN {db_prefix}boards AS b ON (m.id_board = b.id_board)
768
		WHERE m.id_member != {int:zero}
769
			AND b.count_posts = {int:zero}' . (!empty($modSettings['recycle_enable']) ? '
770
			AND b.id_board != {int:recycle}' : '') . '
771
		GROUP BY m.id_member',
772
		array(
773
			'zero' => 0,
774
			'string_zero' => '0',
775
			'recycle' => $modSettings['recycle_board'],
776
		)
777
	) !== false;
778
779
	if ($createTemporary)
780
	{
781
		// Outer join the members table on the temporary table finding the members that
782
		// have a post count but no posts in the message table
783
		$members = $db->fetchQueryCallback('
784
			SELECT mem.id_member, mem.posts
785
			FROM {db_prefix}members AS mem
786
				LEFT OUTER JOIN {db_prefix}tmp_maint_recountposts AS res ON (res.id_member = mem.id_member)
787
			WHERE res.id_member IS NULL
788
				AND mem.posts != {int:zero}',
789
			array(
790
				'zero' => 0,
791
			),
792
			function ($row)
793
			{
794
				// Set the post count to zero for any delinquents we may have found
795
				return $row['id_member'];
796
			}
797
		);
798
799
		if (!empty($members))
800
		{
801
			require_once(SUBSDIR . '/Members.subs.php');
802
			updateMemberData($members, array('posts' => 0));
803
		}
804
	}
805
}
806
807
/**
808
 * Removing old and inactive members
809
 *
810
 * @package Maintenance
811
 * @param string $type
812
 * @param int[] $groups
813
 * @param int $time_limit
814
 * @return array
815
 */
816
function purgeMembers($type, $groups, $time_limit)
817
{
818
	$db = database();
819
820
	$where_vars = array(
821
		'time_limit' => $time_limit,
822
	);
823
	if ($type == 'activated')
824
	{
825
		$where = 'mem.date_registered < {int:time_limit} AND mem.is_activated = {int:is_activated}';
826
		$where_vars['is_activated'] = 0;
827
	}
828
	else
829
		$where = 'mem.last_login < {int:time_limit} AND (mem.last_login != 0 OR mem.date_registered < {int:time_limit})';
830
831
	// Need to get *all* groups then work out which (if any) we avoid.
832
	$request = $db->query('', '
833
		SELECT id_group, group_name, min_posts
834
		FROM {db_prefix}membergroups',
835
		array(
836
		)
837
	);
838
	while ($row = $db->fetch_assoc($request))
839
	{
840
		// Avoid this one?
841
		if (!in_array($row['id_group'], $groups))
842
		{
843
			// Post group?
844
			if ($row['min_posts'] != -1)
845
			{
846
				$where .= ' AND mem.id_post_group != {int:id_post_group_' . $row['id_group'] . '}';
847
				$where_vars['id_post_group_' . $row['id_group']] = $row['id_group'];
848
			}
849
			else
850
			{
851
				$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';
852
				$where_vars['id_group_' . $row['id_group']] = $row['id_group'];
853
			}
854
		}
855
	}
856
	$db->free_result($request);
857
858
	// If we have ungrouped unselected we need to avoid those guys.
859
	if (!in_array(0, $groups))
860
	{
861
		$where .= ' AND (mem.id_group != 0 OR mem.additional_groups != {string:blank_add_groups})';
862
		$where_vars['blank_add_groups'] = '';
863
	}
864
865
	// Select all the members we're about to remove...
866
	$request = $db->query('', '
867
		SELECT mem.id_member, COALESCE(m.id_member, 0) AS is_mod
868
		FROM {db_prefix}members AS mem
869
			LEFT JOIN {db_prefix}moderators AS m ON (m.id_member = mem.id_member)
870
		WHERE ' . $where,
871
		$where_vars
872
	);
873
	$members = array();
874
	while ($row = $db->fetch_assoc($request))
875
	{
876
		if (!$row['is_mod'] || !in_array(3, $groups))
877
			$members[] = $row['id_member'];
878
	}
879
	$db->free_result($request);
880
881
	return $members;
882
}