updateAllSignatures()   F
last analyzed

Complexity

Conditions 70
Paths 3602

Size

Total Lines 279
Code Lines 122

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 4970

Importance

Changes 0
Metric Value
cc 70
eloc 122
nc 3602
nop 1
dl 0
loc 279
ccs 0
cts 120
cp 0
crap 4970
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
 * This file provides utility functions and db function for the profile functions,
5
 * notably, but not exclusively, deals with custom profile fields
6
 *
7
 * @package   ElkArte Forum
8
 * @copyright ElkArte Forum contributors
9
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
10
 *
11
 * This file contains code covered by:
12
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
13
 *
14
 * @version 2.0 dev
15
 *
16
 */
17
18
use ElkArte\Helper\Util;
19
20
/**
21
 * Loads the signature from 50 members per request
22
 * Used in ManageFeatures to apply signature settings to all members
23
 *
24
 * @param int $start_member
25
 * @return array
26
 */
27
function getSignatureFromMembers($start_member)
28
{
29
	$db = database();
30
31
	$members = array();
32
33
	$db->fetchQuery('
34
		SELECT 
35
			id_member, signature
36
		FROM {db_prefix}members
37
		WHERE id_member BETWEEN ' . $start_member . ' AND ' . $start_member . ' + 49
38
			AND id_group != {int:admin_group}
39
			AND FIND_IN_SET({int:admin_group}, additional_groups) = 0',
40
		array(
41
			'admin_group' => 11,
42
		)
43
	)->fetch_callback(
44
		function ($row) use (&$members) {
45
			$members[$row['id_member']]['id_member'] = $row['id_member'];
46
			$members[$row['id_member']]['signature'] = $row['signature'];
47
		}
48
	);
49
50
	return $members;
51
}
52
53
/**
54
 * Updates the signature from a given member
55
 *
56
 * @param int $id_member
57
 * @param string $signature
58
 */
59
function updateSignature($id_member, $signature)
60
{
61
	require_once(SUBSDIR . '/Members.subs.php');
62
	updateMemberData($id_member, array('signature' => $signature));
63
}
64
65
/**
66
 * Update all signatures given a new set of constraints
67
 *
68
 * @param int $applied_sigs
69
 */
70
function updateAllSignatures($applied_sigs)
71
{
72
	global $context, $modSettings;
73
74
	require_once(SUBSDIR . '/Members.subs.php');
75
	$sig_start = time();
76
77
	// This is horrid - but I suppose some people will want the option to do it.
78
	$done = false;
79
	$context['max_member'] = maxMemberID();
80
81
	// Load all the signature settings.
82
	list ($sig_limits, $sig_bbc) = explode(':', $modSettings['signature_settings']);
83
	$sig_limits = explode(',', $sig_limits);
84
	$disabledTags = !empty($sig_bbc) ? explode(',', $sig_bbc) : array();
85
86
	// @todo temporary since it does not work, and seriously why would you do this?
87
	$disabledTags[] = 'footnote';
88
89
	while (!$done)
90
	{
91
		// No changed signatures yet
92
		$changes = array();
93
94
		// Get a group of member signatures, 50 at a clip
95
		$update_sigs = getSignatureFromMembers($applied_sigs);
96
97
		if (empty($update_sigs))
98
		{
99
			$done = true;
100
		}
101
102
		foreach ($update_sigs as $row)
103
		{
104
			// Apply all the rules we can realistically do.
105
			$sig = strtr($row['signature'], array('<br />' => "\n"));
106
107
			// Max characters...
108
			if (!empty($sig_limits[1]))
109
			{
110
				$sig = Util::substr($sig, 0, (int) $sig_limits[1]);
111
			}
112
113
			// Max lines...
114
			if (!empty($sig_limits[2]))
115
			{
116
				$count = 0;
117
				$str_len = strlen($sig);
118
				for ($i = 0; $i < $str_len; $i++)
119
				{
120
					if ($sig[$i] === "\n")
121
					{
122
						$count++;
123
						if ($count >= $sig_limits[2])
124
						{
125
							$sig = substr($sig, 0, $i) . strtr(substr($sig, $i), array("\n" => ' '));
126
						}
127
					}
128
				}
129
			}
130
131
			// Max text size
132
			if (!empty($sig_limits[7]) && preg_match_all('~\[size=([\d\.]+)?(px|pt|em|x-large|larger)?~i', $sig, $matches) !== false && isset($matches[2]))
133
			{
134
				// Same as parse_bbc
135
				$sizes = array(1 => 0.7, 2 => 1.0, 3 => 1.35, 4 => 1.45, 5 => 2.0, 6 => 2.65, 7 => 3.95);
136
137
				foreach ($matches[1] as $ind => $size)
138
				{
139
					$limit_broke = 0;
140
141
					// Just specifying as [size=x]?
142
					if (empty($matches[2][$ind]))
143
					{
144
						$matches[2][$ind] = 'em';
145
						$size = $sizes[(int) $size] ?? 0;
146
					}
147
148
					// Attempt to allow all sizes of abuse, so to speak.
149
					if ($matches[2][$ind] == 'px' && $size > $sig_limits[7])
150
					{
151
						$limit_broke = $sig_limits[7] . 'px';
152
					}
153
					elseif ($matches[2][$ind] == 'pt' && $size > ($sig_limits[7] * 0.75))
154
					{
155
						$limit_broke = ((int) $sig_limits[7] * 0.75) . 'pt';
156
					}
157
					elseif ($matches[2][$ind] == 'em' && $size > ((float) $sig_limits[7] / 16))
158
					{
159
						$limit_broke = ((float) $sig_limits[7] / 16) . 'em';
160
					}
161
					elseif ($matches[2][$ind] != 'px' && $matches[2][$ind] != 'pt' && $matches[2][$ind] != 'em' && $sig_limits[7] < 18)
162
					{
163
						$limit_broke = 'large';
164
					}
165
166
					if ($limit_broke)
167
					{
168
						$sig = str_replace($matches[0][$ind], '[size=' . $sig_limits[7] . 'px', $sig);
169
					}
170
				}
171
			}
172
173
			// Stupid images - this is stupidly, stupidly challenging.
174
			if ((!empty($sig_limits[3]) || !empty($sig_limits[5]) || !empty($sig_limits[6])))
175
			{
176
				$replaces = array();
177
				$img_count = 0;
178
179
				// Get all BBC tags...
180
				preg_match_all('~\[img(\s+width=([\d]+))?(\s+height=([\d]+))?(\s+width=([\d]+))?\s*\](?:<br />)*([^<">]+?)(?:<br />)*\[/img\]~i', $sig, $matches);
181
182
				// ... and all HTML ones.
183
				preg_match_all('~&lt;img\s+src=(?:&quot;)?((?:http://|ftp://|https://|ftps://).+?)(?:&quot;)?(?:\s+alt=(?:&quot;)?(.*?)(?:&quot;)?)?(?:\s?/)?&gt;~i', $sig, $matches2, PREG_PATTERN_ORDER);
184
185
				// And stick the HTML in the BBC.
186
				if (!empty($matches2))
187
				{
188
					foreach ($matches2[0] as $ind => $dummy)
189
					{
190
						$matches[0][] = $matches2[0][$ind];
191
						$matches[1][] = '';
192
						$matches[2][] = '';
193
						$matches[3][] = '';
194
						$matches[4][] = '';
195
						$matches[5][] = '';
196
						$matches[6][] = '';
197
						$matches[7][] = $matches2[1][$ind];
198
					}
199
				}
200
201
				// Try to find all the images!
202
				if (!empty($matches))
203
				{
204
					$image_count_holder = array();
205
					foreach ($matches[0] as $key => $image)
206
					{
207
						$width = -1;
208
						$height = -1;
209
						$img_count++;
210
211
						// Too many images?
212
						if (!empty($sig_limits[3]) && $img_count > $sig_limits[3])
213
						{
214
							// If we've already had this before we only want to remove the excess.
215
							if (isset($image_count_holder[$image]))
216
							{
217
								$img_offset = -1;
218
								$rep_img_count = 0;
219
								while ($img_offset !== false)
220
								{
221
									$img_offset = strpos($sig, $image, $img_offset + 1);
222
									$rep_img_count++;
223
									if ($rep_img_count > $image_count_holder[$image])
224
									{
225
										// Only replace the excess.
226
										$sig = substr($sig, 0, $img_offset) . str_replace($image, '', substr($sig, $img_offset));
227
228
										// Stop looping.
229
										$img_offset = false;
230
									}
231
								}
232
							}
233
							else
234
							{
235
								$replaces[$image] = '';
236
							}
237
238
							continue;
239
						}
240
241
						// Does it have predefined restraints? Width first.
242
						if ($matches[6][$key])
243
						{
244
							$matches[2][$key] = $matches[6][$key];
245
						}
246
247
						if ($matches[2][$key] && $sig_limits[5] && $matches[2][$key] > $sig_limits[5])
248
						{
249
							$width = $sig_limits[5];
250
							$matches[4][$key] *= $width / $matches[2][$key];
251
						}
252
						elseif ($matches[2][$key])
253
						{
254
							$width = $matches[2][$key];
255
						}
256
257
						// ... and height.
258
						if ($matches[4][$key] && $sig_limits[6] && $matches[4][$key] > $sig_limits[6])
259
						{
260
							$height = $sig_limits[6];
261
							if ($width != -1)
262
							{
263
								$width *= $height / $matches[4][$key];
264
							}
265
						}
266
						elseif ($matches[4][$key])
267
						{
268
							$height = $matches[4][$key];
269
						}
270
271
						// If the dimensions are still not fixed - we need to check the actual image.
272
						if (($width == -1 && $sig_limits[5]) || ($height == -1 && $sig_limits[6]))
273
						{
274
							// We'll mess up with images, who knows.
275
							require_once(SUBSDIR . '/Attachments.subs.php');
276
277
							$sizes = url_image_size($matches[7][$key]);
278
							if (is_array($sizes))
279
							{
280
								// Too wide?
281
								if ($sizes[0] > $sig_limits[5] && $sig_limits[5])
282
								{
283
									$width = $sig_limits[5];
284
									$sizes[1] *= $width / $sizes[0];
285
								}
286
287
								// Too high?
288
								if ($sizes[1] > $sig_limits[6] && $sig_limits[6])
289
								{
290
									$height = $sig_limits[6];
291
									if ($width == -1)
292
									{
293
										$width = $sizes[0];
294
									}
295
									$width *= $height / $sizes[1];
296
								}
297
								elseif ($width != -1)
298
								{
299
									$height = $sizes[1];
300
								}
301
							}
302
						}
303
304
						// Did we come up with some changes? If so remake the string.
305
						if ($width != -1 || $height != -1)
306
						{
307
							$replaces[$image] = '[img' . ($width != -1 ? ' width=' . round($width) : '') . ($height != -1 ? ' height=' . round($height) : '') . ']' . $matches[7][$key] . '[/img]';
308
						}
309
310
						// Record that we got one.
311
						$image_count_holder[$image] = isset($image_count_holder[$image]) ? $image_count_holder[$image] + 1 : 1;
312
					}
313
314
					if (!empty($replaces))
315
					{
316
						$sig = str_replace(array_keys($replaces), array_values($replaces), $sig);
317
					}
318
				}
319
			}
320
321
			// Try to fix disabled tags.
322
			if (!empty($disabledTags))
323
			{
324
				$sig = preg_replace('~\[(?:' . implode('|', $disabledTags) . ').+?\]~i', '', $sig);
325
				$sig = preg_replace('~\[/(?:' . implode('|', $disabledTags) . ')\]~i', '', $sig);
326
			}
327
328
			$sig = strtr($sig, array("\n" => '<br />'));
329
			call_integration_hook('integrate_apply_signature_settings', array(&$sig, $sig_limits, $disabledTags));
330
			if ($sig != $row['signature'])
331
			{
332
				$changes[$row['id_member']] = $sig;
333
			}
334
		}
335
336
		// Do we need to delete what we have?
337
		if (!empty($changes))
338
		{
339
			foreach ($changes as $id => $sig)
340
			{
341
				updateSignature($id, $sig);
342
			}
343
		}
344
345
		$applied_sigs += 50;
346
		if (!$done)
347
		{
348
			pauseSignatureApplySettings($applied_sigs, $sig_start);
349
		}
350
	}
351
}
352
353
/**
354
 * Callback for createList() in displaying profile fields
355
 * Can be used to load standard or custom fields by setting the $standardFields flag
356
 *
357
 * @param int $start The item to start with (for pagination purposes)
358
 * @param int $items_per_page The number of items to show per page
359
 * @param string $sort A string indicating how to sort the results
360
 * @param bool $standardFields
361
 *
362
 * @return array
363
 */
364
function list_getProfileFields($start, $items_per_page, $sort, $standardFields)
365
{
366
	global $txt, $modSettings;
367
368
	$db = database();
369
370
	$list = array();
371
372
	if ($standardFields)
373
	{
374
		$standard_fields = array('website', 'posts', 'warning_status', 'date_registered', 'action');
375
		$fields_no_registration = array('posts', 'warning_status', 'date_registered', 'action');
376
		$disabled_fields = isset($modSettings['disabled_profile_fields']) ? explode(',', $modSettings['disabled_profile_fields']) : array();
377
		$registration_fields = isset($modSettings['registration_fields']) ? explode(',', $modSettings['registration_fields']) : array();
378
379
		foreach ($standard_fields as $field)
380
		{
381
			$list[] = array(
382
				'id' => $field,
383
				'label' => $txt['standard_profile_field_' . $field] ?? ($txt[$field] ?? $field),
384
				'disabled' => in_array($field, $disabled_fields),
385
				'on_register' => in_array($field, $registration_fields) && !in_array($field, $fields_no_registration),
386
				'can_show_register' => !in_array($field, $fields_no_registration),
387
			);
388
		}
389
	}
390
	else
391
	{
392
		// Load all the fields.
393
		$db->fetchQuery('
394
			SELECT 
395
				id_field, col_name, field_name, field_desc, field_type, active, placement, vieworder
396
			FROM {db_prefix}custom_fields
397
			ORDER BY {raw:sort}, vieworder ASC
398
			LIMIT {int:start}, {int:items_per_page}',
399
			array(
400
				'sort' => $sort,
401
				'start' => $start,
402
				'items_per_page' => $items_per_page,
403
			)
404
		)->fetch_callback(
405
			function ($row) use (&$list) {
406
				$list[$row['id_field']] = $row;
407
			}
408
		);
409
	}
410
411
	return $list;
412
}
413
414
/**
415
 * Callback for createList().
416
 */
417
function list_getProfileFieldSize()
418
{
419
	$db = database();
420
421
	$request = $db->query('', '
422
		SELECT 
423
			COUNT(*)
424
		FROM {db_prefix}custom_fields',
425
		array()
426
	);
427
	list ($numProfileFields) = $request->fetch_row();
428
	$request->free_result();
429
430
	return $numProfileFields;
431
}
432
433
/**
434
 * Loads the profile field properties from a given field id
435
 *
436
 * @param int $id_field
437
 * @return array $field
438
 */
439
function getProfileField($id_field)
440
{
441
	$db = database();
442
443
	$field = array();
444
445
	// The fully-qualified name for rows is here because it's a reserved word in Mariadb 10.2.4+ and quoting would be different for MySQL/Mariadb and PSQL
446
	$db->fetchQuery('
447
		SELECT
448
			id_field, col_name, field_name, field_desc, field_type, field_length, field_options,
449
			show_reg, show_display, show_memberlist, show_profile, private, active, default_value, can_search,
450
			bbc, mask, enclose, placement, vieworder, {db_prefix}custom_fields.rows, cols
451
		FROM {db_prefix}custom_fields
452
		WHERE id_field = {int:current_field}',
453
		array(
454
			'current_field' => $id_field,
455
		)
456
	)->fetch_callback(
457
		function ($row) use (&$field) {
458
			$field = array(
459
				'name' => $row['field_name'],
460
				'desc' => $row['field_desc'],
461
				'colname' => $row['col_name'],
462
				'profile_area' => $row['show_profile'],
463
				'reg' => $row['show_reg'],
464
				'display' => $row['show_display'],
465
				'memberlist' => $row['show_memberlist'],
466
				'type' => $row['field_type'],
467
				'max_length' => $row['field_length'],
468
				'rows' => $row['rows'],
469
				'cols' => $row['cols'],
470
				'bbc' => $row['bbc'] ? true : false,
471
				'default_check' => $row['field_type'] === 'check' && $row['default_value'],
472
				'default_select' => $row['field_type'] === 'select' || $row['field_type'] === 'radio' ? $row['default_value'] : '',
473
				'show_nodefault' => $row['field_type'] === 'select' || $row['field_type'] === 'radio',
474
				'default_value' => $row['default_value'],
475
				'options' => strlen($row['field_options']) > 1 ? explode(',', $row['field_options']) : array('', '', ''),
476
				'active' => $row['active'],
477
				'private' => $row['private'],
478
				'can_search' => $row['can_search'],
479
				'mask' => $row['mask'],
480
				'regex' => strpos($row['mask'], 'regex') === 0 ? substr($row['mask'], 5) : '',
481
				'enclose' => $row['enclose'],
482
				'placement' => $row['placement'],
483
			);
484
		}
485
	);
486
487
	return $field;
488
}
489
490
/**
491
 * Make sure a profile field is unique
492
 *
493
 * @param string $colname
494
 * @param string $initial_colname
495
 * @param bool $unique
496
 * @return bool
497
 */
498
function ensureUniqueProfileField($colname, $initial_colname, $unique = false)
499
{
500
	$db = database();
501
	// Make sure this is unique.
502
	// @todo This may not be the most efficient way to do this.
503
	for ($i = 0; !$unique && $i < 9; $i++)
504
	{
505
		$request = $db->query('', '
506
			SELECT 
507
				id_field
508
			FROM {db_prefix}custom_fields
509
			WHERE col_name = {string:current_column}',
510
			array(
511
				'current_column' => $colname,
512
			)
513
		);
514
		if ($request->num_rows() === 0)
515
		{
516
			$unique = true;
517
		}
518
		else
519
		{
520
			$colname = $initial_colname . $i;
521
		}
522
		$request->free_result();
523
	}
524
525
	return $unique;
526
}
527
528
/**
529
 * Update the profile fields name
530
 *
531
 * @param string $key
532
 * @param mixed[] $newOptions
533
 * @param string $name
534
 * @param string $option
535
 */
536
function updateRenamedProfileField($key, $newOptions, $name, $option)
537
{
538
	$db = database();
539
540
	$db->query('', '
541
		UPDATE {db_prefix}custom_fields_data
542
		SET value = {string:new_value}
543
		WHERE variable = {string:current_column}
544
			AND value = {string:old_value}
545
			AND id_member > {int:no_member}',
546
		array(
547
			'no_member' => 0,
548
			'new_value' => $newOptions[$key],
549
			'current_column' => $name,
550
			'old_value' => $option,
551
		)
552
	);
553
}
554
555
/**
556
 * Update the custom profile fields active status on/off
557
 *
558
 * @param int[] $enabled
559
 */
560
function updateRenamedProfileStatus($enabled)
561
{
562
	$db = database();
563
564
	// Do the updates
565
	$db->query('', '
566
		UPDATE {db_prefix}custom_fields
567
		SET active = CASE WHEN id_field IN ({array_int:id_cust_enable}) THEN 1 ELSE 0 END',
568
		array(
569
			'id_cust_enable' => $enabled,
570
		)
571
	);
572
}
573
574
/**
575
 * Update the profile field
576
 *
577
 * @param mixed[] $field_data
578
 */
579
function updateProfileField($field_data)
580
{
581
	$db = database();
582
583
	// The fully-qualified name for rows is here because it's a reserved word in Mariadb 10.2.4+ and quoting would be different for MySQL/Mariadb and PSQL
584
	$db->query('', '
585
		UPDATE {db_prefix}custom_fields
586
		SET
587
			field_name = {string:field_name}, field_desc = {string:field_desc},
588
			field_type = {string:field_type}, field_length = {int:field_length},
589
			field_options = {string:field_options}, show_reg = {int:show_reg},
590
			show_display = {int:show_display}, show_memberlist = {int:show_memberlist},
591
			show_profile = {string:show_profile}, private = {int:private},
592
			active = {int:active}, default_value = {string:default_value},
593
			can_search = {int:can_search}, bbc = {int:bbc}, mask = {string:mask},
594
			enclose = {string:enclose}, placement = {int:placement}, {db_prefix}custom_fields.rows = {int:rows},
595
			cols = {int:cols}
596
		WHERE id_field = {int:current_field}',
597
		array(
598
			'field_length' => $field_data['field_length'],
599
			'show_reg' => $field_data['show_reg'],
600
			'show_display' => $field_data['show_display'],
601
			'show_memberlist' => $field_data['show_memberlist'],
602
			'private' => $field_data['private'],
603
			'active' => $field_data['active'],
604
			'can_search' => $field_data['can_search'],
605
			'bbc' => $field_data['bbc'],
606
			'current_field' => $field_data['current_field'],
607
			'field_name' => $field_data['field_name'],
608
			'field_desc' => $field_data['field_desc'],
609
			'field_type' => $field_data['field_type'],
610
			'field_options' => $field_data['field_options'],
611
			'show_profile' => $field_data['show_profile'],
612
			'default_value' => $field_data['default_value'],
613
			'mask' => $field_data['mask'],
614
			'enclose' => $field_data['enclose'],
615
			'placement' => $field_data['placement'],
616
			'rows' => $field_data['rows'],
617
			'cols' => $field_data['cols'],
618
		)
619
	);
620
}
621
622
/**
623
 * Updates the viewing order for profile fields
624
 * Done as a CASE WHEN one two three ELSE 0 END in place of many updates
625
 *
626
 * @param string $replace constructed as WHEN fieldname=value THEN new viewvalue WHEN .....
627
 */
628
function updateProfileFieldOrder($replace)
629
{
630
	$db = database();
631
632
	$db->query('', '
633
		UPDATE {db_prefix}custom_fields
634
		SET vieworder = CASE ' . $replace . ' ELSE 0 END',
635
		array('')
636
	);
637
}
638
639
/**
640
 * Deletes selected values from old profile field selects
641
 *
642
 * @param string[] $newOptions
643
 * @param string $fieldname
644
 */
645
function deleteOldProfileFieldSelects($newOptions, $fieldname)
646
{
647
	$db = database();
648
649
	$db->query('', '
650
		DELETE FROM {db_prefix}custom_fields_data
651
		WHERE variable = {string:current_column}
652
			AND value NOT IN ({array_string:new_option_values})
653
			AND id_member > {int:no_member}',
654
		array(
655
			'no_member' => 0,
656
			'new_option_values' => $newOptions,
657
			'current_column' => $fieldname,
658
		)
659
	);
660
}
661
662
/**
663
 * Used to add a new custom profile field
664
 *
665
 * @param mixed[] $field
666
 */
667
function addProfileField($field)
668
{
669
	$db = database();
670
671
	$db->insert('',
672
		'{db_prefix}custom_fields',
673
		array(
674
			'col_name' => 'string', 'field_name' => 'string', 'field_desc' => 'string',
675
			'field_type' => 'string', 'field_length' => 'string', 'field_options' => 'string',
676
			'show_reg' => 'int', 'show_display' => 'int', 'show_memberlist' => 'int', 'show_profile' => 'string',
677
			'private' => 'int', 'active' => 'int', 'default_value' => 'string', 'can_search' => 'int',
678
			'bbc' => 'int', 'mask' => 'string', 'enclose' => 'string', 'placement' => 'int', 'vieworder' => 'int',
679
			'rows' => 'int', 'cols' => 'int'
680
		),
681
		array(
682
			$field['col_name'], $field['field_name'], $field['field_desc'],
683
			$field['field_type'], $field['field_length'], $field['field_options'],
684
			$field['show_reg'], $field['show_display'], $field['show_memberlist'], $field['show_profile'],
685
			$field['private'], $field['active'], $field['default_value'], $field['can_search'],
686
			$field['bbc'], $field['mask'], $field['enclose'], $field['placement'], $field['vieworder'],
687
			$field['rows'], $field['cols']
688
		),
689
		array('id_field')
690
	);
691
}
692
693
/**
694
 * Delete all user data for a specified custom profile field
695
 *
696
 * @param string $name
697
 */
698
function deleteProfileFieldUserData($name)
699
{
700
	$db = database();
701
702
	// Delete the user data first.
703
	$db->query('', '
704
		DELETE FROM {db_prefix}custom_fields_data
705
		WHERE variable = {string:current_column}
706
			AND id_member > {int:no_member}',
707
		array(
708
			'no_member' => 0,
709
			'current_column' => $name,
710
		)
711
	);
712
}
713
714
/**
715
 * Deletes a custom profile field.
716
 *
717
 * @param int $id
718
 */
719
function deleteProfileField($id)
720
{
721
	$db = database();
722
723
	$db->query('', '
724
		DELETE FROM {db_prefix}custom_fields
725
		WHERE id_field = {int:current_field}',
726
		array(
727
			'current_field' => $id,
728
		)
729
	);
730
}
731
732
/**
733
 * Update the display cache, needed after editing or deleting a custom profile field
734
 */
735
function updateDisplayCache()
736
{
737
	$db = database();
738
739
	$fields = $db->fetchQuery('
740
		SELECT 
741
			col_name, field_name, field_type, bbc, enclose, placement, vieworder
742
		FROM {db_prefix}custom_fields
743
		WHERE show_display = {int:is_displayed}
744
			AND active = {int:active}
745
			AND private != {int:not_owner_only}
746
			AND private != {int:not_admin_only}
747
		ORDER BY vieworder',
748
		array(
749
			'is_displayed' => 1,
750
			'active' => 1,
751
			'not_owner_only' => 2,
752
			'not_admin_only' => 3,
753
		)
754
	)->fetch_callback(
755
		function ($row) {
756
			return array(
757
				'colname' => strtr($row['col_name'], array('|' => '', ';' => '')),
758
				'title' => strtr($row['field_name'], array('|' => '', ';' => '')),
759
				'type' => $row['field_type'],
760
				'bbc' => $row['bbc'] ? 1 : 0,
761
				'placement' => !empty($row['placement']) ? $row['placement'] : 0,
762
				'enclose' => !empty($row['enclose']) ? $row['enclose'] : '',
763
			);
764
		}
765
	);
766
767
	updateSettings(array('displayFields' => serialize($fields)));
768
}
769
770
/**
771
 * Loads all the custom fields in the system, active or not
772
 */
773
function loadAllCustomFields()
774
{
775
	$db = database();
776
777
	// Get the names of any custom fields.
778
	$custom_field_titles = array();
779
	$db->fetchQuery('
780
		SELECT
781
			col_name, field_name, bbc
782
		FROM {db_prefix}custom_fields',
783
		array()
784
	)->fetch_callback(
785
		function ($row) use (&$custom_field_titles) {
786
			$custom_field_titles['customfield_' . $row['col_name']] = array(
787
				'title' => $row['field_name'],
788
				'parse_bbc' => $row['bbc'],
789
			);
790
		}
791
	);
792
793
	return $custom_field_titles;
794
}
795
796
/**
797
 * Load all the available mention types
798
 *
799
 * What it does:
800
 *
801
 * - Scans the ElkArte\Mentions\MentionType\Notifications directory for available classes
802
 *
803
 * @return array
804
 */
805
function getAvailableNotifications()
806
{
807
	$glob = new GlobIterator(SOURCEDIR . '/ElkArte/Mentions/MentionType/Notification/*.php', FilesystemIterator::SKIP_DOTS);
808
	$types = array();
809
810
	// For each file found, return its FQN
811
	foreach ($glob as $file)
812
	{
813
		$class_name = '\\ElkArte\\Mentions\\MentionType\\Notification\\' . $file->getBasename('.php');
814
		$types[] = $class_name;
815
	}
816
817
	return $types;
818
}
819
820
/**
821 2
 * Returns the modules for the given mentions
822 2
 *
823
 * What it does:
824
 *
825 2
 * - Calls each modules static function ::getModules
826
 * - Called from ManageFeatures as part of notification settings
827
 *
828
 * @param string[] $enabled_mentions
829
 *
830
 * @return array
831 2
 */
832
function getMentionsModules($enabled_mentions)
833
{
834
	$modules = array();
835
836
	foreach ($enabled_mentions as $mention)
837
	{
838
		$class_name = '\\ElkArte\\Mentions\\MentionType\\Event\\' . ucfirst($mention);
839
		if (class_exists($class_name))
840
		{
841
			$modules = $class_name::getModules($modules);
842
		}
843
	}
844
845
	return $modules;
846
}
847
848
/**
849
 * Loads available frontpage controllers for selection in the look/layout area of the ACP
850
 *
851
 * What it does:
852
 *
853
 * - Scans controllerdir and addonsdir for .controller.php files
854
 * - Checks if found files have a static frontPageOptions method
855
 *
856
 * @return array
857
 */
858
function getFrontPageControllers()
859
{
860
	global $txt;
861
862
	$classes = array();
863
864
	$glob = new GlobIterator(CONTROLLERDIR . '/*.php', FilesystemIterator::SKIP_DOTS);
865
	$classes += scanFileSystemForControllers($glob, '\\ElkArte\\Controller\\');
866
867
	$glob = new GlobIterator(ADDONSDIR . '/*/controllers/*.php', FilesystemIterator::SKIP_DOTS);
868
	$classes += scanFileSystemForControllers($glob, '\\ElkArte\\Addon\\');
869
870
	$config_vars = array(array('select', 'front_page', $classes));
871
	array_unshift($config_vars[0][2], $txt['default']);
872
873
	foreach (array_keys($classes) as $class_name)
874 2
	{
875
		$options = $class_name::frontPageOptions();
876 2
		if (!empty($options))
877
		{
878 2
			$config_vars = array_merge($config_vars, $options);
879 2
		}
880
	}
881 2
882 2
	return $config_vars;
883
}
884 2
885 2
/**
886
 *
887 2
 * @param \GlobIterator $iterator
888
 * @param string $namespace
889
 *
890
 * @return array
891
 */
892
function scanFileSystemForControllers($iterator, $namespace = '')
893
{
894
	global $txt;
895
896 2
	$types = [];
897
898
	foreach ($iterator as $file)
899
	{
900
		$fileName =  $file->getBasename('.php');
901
		$className = $namespace . $fileName;
902
903
		if (!class_exists($className))
904
		{
905
			continue;
906
		}
907
908 2
		if (is_subclass_of($className, '\\ElkArte\\AbstractController') && $className::canFrontPage())
909
		{
910 2
			// Temporary
911
			$txtString = $fileName . '_Controller';
912 2
			if (!isset($txt[$txtString]))
913
			{
914
				continue;
915
			}
916
917
			$types[$className] = $txt[$txtString];
918
		}
919
	}
920
921
	return $types;
922
}
923
924
/**
925
 * Just pause the signature applying thing.
926
 *
927
 * @param int $applied_sigs
928
 * @param int $sig_start
929
 * @todo Merge with other pause functions?
930
 *    pausePermsSave(), pauseAttachmentMaintenance(), pauseRepairProcess()
931
 *
932
 * @todo Move to subs file
933 2
 */
934
function pauseSignatureApplySettings($applied_sigs, $sig_start)
935
{
936
	global $context, $txt;
937
938
	// Try get more time...
939
	detectServer()->setTimeLimit(600);
940
941
	// Have we exhausted all the time we allowed?
942
	if (time() - array_sum(explode(' ', $sig_start)) < 3)
943
	{
944
		return;
945
	}
946
947
	$context['continue_get_data'] = '?action=admin;area=featuresettings;sa=sig;apply;step=' . $applied_sigs . ';' . $context['session_var'] . '=' . $context['session_id'];
948
	$context['page_title'] = $txt['not_done_title'];
949
	$context['continue_post_data'] = '';
950
	$context['continue_countdown'] = '2';
951
	$context['sub_template'] = 'not_done';
952
953
	// Specific stuff to not break this template!
954
	$context[$context['admin_menu_name']]['current_subsection'] = 'sig';
955
956
	// Get the right percent.
957
	$context['continue_percent'] = round(($applied_sigs / $context['max_member']) * 100);
958
959
	// Never more than 100%!
960
	$context['continue_percent'] = min($context['continue_percent'], 100);
961
962
	obExit();
963
}
964