1<?php
2/**
3 * MyBB 1.8
4 * Copyright 2014 MyBB Group, All Rights Reserved
5 *
6 * Website: http://www.mybb.com
7 * License: http://www.mybb.com/about/license
8 *
9 */
10
11// Disallow direct access to this file for security reasons
12if(!defined("IN_MYBB"))
13{
14	die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
15}
16
17/**
18 * User handling class, provides common structure to handle user data.
19 *
20 */
21class UserDataHandler extends DataHandler
22{
23	/**
24	* The language file used in the data handler.
25	*
26	* @var string
27	*/
28	public $language_file = 'datahandler_user';
29
30	/**
31	* The prefix for the language variables used in the data handler.
32	*
33	* @var string
34	*/
35	public $language_prefix = 'userdata';
36
37	/**
38	 * Array of data inserted in to a user.
39	 *
40	 * @var array
41	 */
42	public $user_insert_data = array();
43
44	/**
45	 * Array of data used to update a user.
46	 *
47	 * @var array
48	 */
49	public $user_update_data = array();
50
51	/**
52	 * User ID currently being manipulated by the datahandlers.
53	 *
54	 * @var int
55	 */
56	public $uid = 0;
57
58	/**
59	 * Values to be returned after inserting/deleting an user.
60	 *
61	 * @var array
62	 */
63	public $return_values = array();
64
65	/**
66	 * @var array
67	 */
68	var $delete_uids = array();
69
70	/**
71	 * @var int
72	 */
73	var $deleted_users = 0;
74
75	/**
76	 * Verifies if a username is valid or invalid.
77	 *
78	 * @return boolean True when valid, false when invalid.
79	 */
80	function verify_username()
81	{
82		global $mybb;
83
84		$username = &$this->data['username'];
85		require_once MYBB_ROOT.'inc/functions_user.php';
86
87		// Fix bad characters
88		$username = trim_blank_chrs($username);
89		$username = str_replace(array(unichr(160), unichr(173), unichr(0xCA), dec_to_utf8(8238), dec_to_utf8(8237), dec_to_utf8(8203)), array(" ", "-", "", "", "", ""), $username);
90
91		// Remove multiple spaces from the username
92		$username = preg_replace("#\s{2,}#", " ", $username);
93
94		// Check if the username is not empty.
95		if($username == '')
96		{
97			$this->set_error('missing_username');
98			return false;
99		}
100
101		// Check if the username belongs to the list of banned usernames.
102		if(is_banned_username($username, true))
103		{
104			$this->set_error('banned_username');
105			return false;
106		}
107
108		// Check for certain characters in username (<, >, &, commas and slashes)
109		if(strpos($username, "<") !== false || strpos($username, ">") !== false || strpos($username, "&") !== false || my_strpos($username, "\\") !== false || strpos($username, ";") !== false || strpos($username, ",") !== false || !validate_utf8_string($username, false, false))
110		{
111			$this->set_error("bad_characters_username");
112			return false;
113		}
114
115		// Check if the username is of the correct length.
116		if(($mybb->settings['maxnamelength'] != 0 && my_strlen($username) > $mybb->settings['maxnamelength']) || ($mybb->settings['minnamelength'] != 0 && my_strlen($username) < $mybb->settings['minnamelength']))
117		{
118			$this->set_error('invalid_username_length', array($mybb->settings['minnamelength'], $mybb->settings['maxnamelength']));
119			return false;
120		}
121
122		return true;
123	}
124
125	/**
126	 * Verifies if a usertitle is valid or invalid.
127	 *
128	 * @return boolean True when valid, false when invalid.
129	 */
130	function verify_usertitle()
131	{
132		global $mybb;
133
134		$usertitle = &$this->data['usertitle'];
135
136		// Check if the usertitle is of the correct length.
137		if($mybb->settings['customtitlemaxlength'] != 0 && my_strlen($usertitle) > $mybb->settings['customtitlemaxlength'])
138		{
139			$this->set_error('invalid_usertitle_length', $mybb->settings['customtitlemaxlength']);
140			return false;
141		}
142
143		return true;
144	}
145
146	/**
147	 * Verifies if a username is already in use or not.
148	 *
149	 * @return boolean False when the username is not in use, true when it is.
150	 */
151	function verify_username_exists()
152	{
153		$username = &$this->data['username'];
154
155		$user = get_user_by_username(trim($username));
156
157		if(!empty($this->data['uid']) && !empty($user['uid']) && $user['uid'] == $this->data['uid'])
158		{
159			unset($user);
160		}
161
162		if(!empty($user['uid']))
163		{
164			$this->set_error("username_exists", array($username));
165			return true;
166		}
167
168		return false;
169	}
170
171	/**
172	* Verifies if a new password is valid or not.
173	*
174	* @return boolean True when valid, false when invalid.
175	*/
176	function verify_password()
177	{
178		global $mybb;
179
180		$user = &$this->data;
181
182		// Always check for the length of the password.
183		if(my_strlen($user['password']) < $mybb->settings['minpasswordlength'] || my_strlen($user['password']) > $mybb->settings['maxpasswordlength'])
184		{
185			$this->set_error('invalid_password_length', array($mybb->settings['minpasswordlength'], $mybb->settings['maxpasswordlength']));
186			return false;
187		}
188
189		// Has the user tried to use their email address or username as a password?
190		if(!empty($user['email']) && !empty($user['username']))
191		{
192			if($user['email'] === $user['password'] || $user['username'] === $user['password']
193				|| strpos($user['password'], $user['email']) !== false || strpos($user['password'], $user['username']) !== false
194				|| strpos($user['email'], $user['password']) !== false || strpos($user['username'], $user['password']) !== false)
195			{
196				$this->set_error('bad_password_security');
197				return false;
198			}
199		}
200
201		// See if the board has "require complex passwords" enabled.
202		if($mybb->settings['requirecomplexpasswords'] == 1)
203		{
204			// Complex passwords required, do some extra checks.
205			// First, see if there is one or more complex character(s) in the password.
206			if(!preg_match("/^.*(?=.{".$mybb->settings['minpasswordlength'].",})(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$/", $user['password']))
207			{
208				$this->set_error('no_complex_characters', array($mybb->settings['minpasswordlength']));
209				return false;
210			}
211		}
212
213		// If we have a "password2" check if they both match
214		if(isset($user['password2']) && $user['password'] !== $user['password2'])
215		{
216			$this->set_error("passwords_dont_match");
217			return false;
218		}
219
220		// Generate the user login key
221		$user['loginkey'] = generate_loginkey();
222
223		// Combine the password and salt
224		$password_fields = create_password($user['password'], false, $user);
225		$user = array_merge($user, $password_fields);
226
227		return true;
228	}
229
230	/**
231	* Verifies usergroup selections and other group details.
232	*
233	* @return boolean True when valid, false when invalid.
234	*/
235	function verify_usergroup()
236	{
237		return true;
238	}
239	/**
240	* Verifies if an email address is valid or not.
241	*
242	* @return boolean True when valid, false when invalid.
243	*/
244	function verify_email()
245	{
246		global $mybb;
247
248		$user = &$this->data;
249
250		// Check if an email address has actually been entered.
251		if(trim_blank_chrs($user['email']) == '')
252		{
253			$this->set_error('missing_email');
254			return false;
255		}
256
257		// Check if this is a proper email address.
258		if(!validate_email_format($user['email']))
259		{
260			$this->set_error('invalid_email_format');
261			return false;
262		}
263
264		// Check banned emails
265		if(is_banned_email($user['email'], true))
266		{
267			$this->set_error('banned_email');
268			return false;
269		}
270
271		// Check signed up emails
272		// Ignore the ACP because the Merge System sometimes produces users with duplicate email addresses (Not A Bug)
273		if($mybb->settings['allowmultipleemails'] == 0 && !defined("IN_ADMINCP"))
274		{
275			$uid = 0;
276			if(isset($user['uid']))
277			{
278				$uid = $user['uid'];
279			}
280			if(email_already_in_use($user['email'], $uid))
281			{
282				$this->set_error('email_already_in_use');
283				return false;
284			}
285		}
286
287		// If we have an "email2", verify it matches the existing email
288		if(isset($user['email2']) && $user['email'] != $user['email2'])
289		{
290			$this->set_error("emails_dont_match");
291			return false;
292		}
293
294		return true;
295	}
296
297	/**
298	* Verifies if a website is valid or not.
299	*
300	* @return boolean True when valid, false when invalid.
301	*/
302	function verify_website()
303	{
304		$website = &$this->data['website'];
305
306		if(!empty($website) && !my_validate_url($website))
307		{
308			$website = 'http://'.$website;
309		}
310
311		if(!empty($website) && !my_validate_url($website))
312		{
313			$this->set_error('invalid_website');
314			return false;
315		}
316
317		return true;
318	}
319
320	/**
321	 * Verifies if an ICQ number is valid or not.
322	 *
323	 * @return boolean True when valid, false when invalid.
324	 */
325	function verify_icq()
326	{
327		$icq = &$this->data['icq'];
328
329		if($icq != '' && !is_numeric($icq))
330		{
331			$this->set_error("invalid_icq_number");
332			return false;
333		}
334		$icq = (int)$icq;
335		return true;
336	}
337
338	/**
339	* Verifies if a birthday is valid or not.
340	*
341	* @return boolean True when valid, false when invalid.
342	*/
343	function verify_birthday()
344	{
345		global $mybb;
346
347		$user = &$this->data;
348		$birthday = &$user['birthday'];
349
350		if(!is_array($birthday))
351		{
352			return true;
353		}
354
355		// Sanitize any input we have
356		$birthday['day'] = (int)$birthday['day'];
357		$birthday['month'] = (int)$birthday['month'];
358		$birthday['year'] = (int)$birthday['year'];
359
360		// Error if a day and month exists, and the birthday day and range is not in range
361		if($birthday['day'] != 0 || $birthday['month'] != 0)
362		{
363			if($birthday['day'] < 1 || $birthday['day'] > 31 || $birthday['month'] < 1 || $birthday['month'] > 12 || ($birthday['month'] == 2 && $birthday['day'] > 29))
364			{
365				$this->set_error("invalid_birthday");
366				return false;
367			}
368		}
369
370		// Check if the day actually exists.
371		$months = get_bdays($birthday['year']);
372		if($birthday['month'] != 0 && $birthday['day'] > $months[$birthday['month']-1])
373		{
374			$this->set_error("invalid_birthday");
375			return false;
376		}
377
378		// Error if a year exists and the year is out of range
379		if($birthday['year'] != 0 && ($birthday['year'] < (date("Y")-100)) || $birthday['year'] > date("Y"))
380		{
381			$this->set_error("invalid_birthday");
382			return false;
383		}
384		elseif($birthday['year'] == date("Y"))
385		{
386			// Error if birth date is in future
387			if($birthday['month'] > date("m") || ($birthday['month'] == date("m") && $birthday['day'] > date("d")))
388			{
389				$this->set_error("invalid_birthday");
390				return false;
391			}
392		}
393
394		// Error if COPPA is on, and the user hasn't verified their age / under 13
395		if($mybb->settings['coppa'] == "enabled" && ($birthday['year'] == 0 || !$birthday['year']))
396		{
397			$this->set_error("invalid_birthday_coppa");
398			return false;
399		}
400		elseif(($mybb->settings['coppa'] == "deny" && $birthday['year'] > (date("Y")-13)) && !is_moderator())
401		{
402			$this->set_error("invalid_birthday_coppa2");
403			return false;
404		}
405
406		// Make the user's birthday field
407		if($birthday['year'] != 0)
408		{
409			// If the year is specified, put together a d-m-y string
410			$user['bday'] = $birthday['day']."-".$birthday['month']."-".$birthday['year'];
411		}
412		elseif($birthday['day'] && $birthday['month'])
413		{
414			// If only a day and month are specified, put together a d-m string
415			$user['bday'] = $birthday['day']."-".$birthday['month']."-";
416		}
417		else
418		{
419			// No field is specified, so return an empty string for an unknown birthday
420			$user['bday'] = '';
421		}
422		return true;
423	}
424
425	/**
426	 * Verifies if the birthday privacy option is valid or not.
427	 *
428	 * @return boolean True when valid, false when invalid.
429	 */
430	function verify_birthday_privacy()
431	{
432		$birthdayprivacy = &$this->data['birthdayprivacy'];
433		$accepted = array(
434					'none',
435					'age',
436					'all');
437
438		if(!in_array($birthdayprivacy, $accepted))
439		{
440			$this->set_error("invalid_birthday_privacy");
441			return false;
442		}
443		else if ($birthdayprivacy == 'age')
444		{
445			$birthdayyear = &$this->data['birthday']['year'];
446			if(empty($birthdayyear))
447			{
448				$this->set_error("conflicted_birthday_privacy");
449				return false;
450			}
451		}
452		return true;
453	}
454
455	/**
456	* Verifies if the post count field is filled in correctly.
457	*
458	* @return boolean True when valid, false when invalid.
459	*/
460	function verify_postnum()
461	{
462		$user = &$this->data;
463
464		if(isset($user['postnum']) && $user['postnum'] < 0)
465		{
466			$this->set_error("invalid_postnum");
467			return false;
468		}
469
470		return true;
471	}
472
473	/**
474	* Verifies if the thread count field is filled in correctly.
475	*
476	* @return boolean True when valid, false when invalid.
477	*/
478	function verify_threadnum()
479	{
480		$user = &$this->data;
481
482		if(isset($user['threadnum']) && $user['threadnum'] < 0)
483		{
484			$this->set_error("invalid_threadnum");
485			return false;
486		}
487
488		return true;
489	}
490
491	/**
492	* Verifies if a profile fields are filled in correctly.
493	*
494	* @return boolean True when valid, false when invalid.
495	*/
496	function verify_profile_fields()
497	{
498		global $db, $cache;
499
500		$user = &$this->data;
501		$profile_fields = &$this->data['profile_fields'];
502
503		// Loop through profile fields checking if they exist or not and are filled in.
504
505		// Fetch all profile fields first.
506		$pfcache = $cache->read('profilefields');
507
508		if(is_array($pfcache))
509		{
510			// Then loop through the profile fields.
511			foreach($pfcache as $profilefield)
512			{
513				if(isset($this->data['profile_fields_editable']) || isset($this->data['registration']) && ($profilefield['required'] == 1 || $profilefield['registration'] == 1))
514				{
515					$profilefield['editableby'] = -1;
516				}
517
518				if(isset($user['usergroup']))
519				{
520					$usergroup = $user['usergroup'];
521				}
522				else
523				{
524					$usergroup = '';
525				}
526				if(isset($user['additionalgroups']))
527				{
528					$additionalgroups = $user['additionalgroups'];
529				}
530				else
531				{
532					$additionalgroups = '';
533				}
534
535				if(!is_member($profilefield['editableby'], array('usergroup' => $usergroup, 'additionalgroups' => $additionalgroups)))
536				{
537					continue;
538				}
539
540				// Does this field have a minimum post count?
541				if(!isset($this->data['profile_fields_editable']) && !empty($profilefield['postnum']) && $profilefield['postnum'] > $user['postnum'])
542				{
543					continue;
544				}
545
546				$profilefield['type'] = htmlspecialchars_uni($profilefield['type']);
547				$profilefield['name'] = htmlspecialchars_uni($profilefield['name']);
548				$thing = explode("\n", $profilefield['type'], "2");
549				$type = trim($thing[0]);
550				$field = "fid{$profilefield['fid']}";
551
552				if(!isset($profile_fields[$field]))
553				{
554					$profile_fields[$field] = '';
555				}
556
557				// If the profile field is required, but not filled in, present error.
558				if($type != "multiselect" && $type != "checkbox")
559				{
560					if(trim($profile_fields[$field]) == "" && $profilefield['required'] == 1 && !defined('IN_ADMINCP') && THIS_SCRIPT != "modcp.php")
561					{
562						$this->set_error('missing_required_profile_field', array($profilefield['name']));
563					}
564				}
565				elseif(($type == "multiselect" || $type == "checkbox") && $profile_fields[$field] == "" && $profilefield['required'] == 1 && !defined('IN_ADMINCP') && THIS_SCRIPT != "modcp.php")
566				{
567					$this->set_error('missing_required_profile_field', array($profilefield['name']));
568				}
569
570				// Sort out multiselect/checkbox profile fields.
571				$options = '';
572				if(($type == "multiselect" || $type == "checkbox") && is_array($profile_fields[$field]))
573				{
574					$expoptions = explode("\n", $thing[1]);
575					$expoptions = array_map('trim', $expoptions);
576					foreach($profile_fields[$field] as $value)
577					{
578						if(!in_array(htmlspecialchars_uni($value), $expoptions))
579						{
580							$this->set_error('bad_profile_field_values', array($profilefield['name']));
581						}
582						if($options)
583						{
584							$options .= "\n";
585						}
586						$options .= $db->escape_string($value);
587					}
588				}
589				elseif($type == "select" || $type == "radio")
590				{
591					$expoptions = explode("\n", $thing[1]);
592					$expoptions = array_map('trim', $expoptions);
593					if(!in_array(htmlspecialchars_uni($profile_fields[$field]), $expoptions) && trim($profile_fields[$field]) != "")
594					{
595						$this->set_error('bad_profile_field_values', array($profilefield['name']));
596					}
597					$options = $db->escape_string($profile_fields[$field]);
598				}
599				else
600				{
601					if($profilefield['maxlength'] > 0 && my_strlen($profile_fields[$field]) > $profilefield['maxlength'])
602					{
603						$this->set_error('max_limit_reached', array($profilefield['name'], $profilefield['maxlength']));
604					}
605
606					if(!empty($profilefield['regex']) && !empty($profile_fields[$field]) && !preg_match("#".$profilefield['regex']."#i", $profile_fields[$field]))
607					{
608						$this->set_error('bad_profile_field_value', array($profilefield['name']));
609					}
610
611					$options = $db->escape_string($profile_fields[$field]);
612				}
613				$user['user_fields'][$field] = $options;
614			}
615		}
616
617		return true;
618	}
619
620	/**
621	* Verifies if an optionally entered referrer exists or not.
622	*
623	* @return boolean True when valid, false when invalid.
624	*/
625	function verify_referrer()
626	{
627		global $db, $mybb;
628
629		$user = &$this->data;
630
631		// Does the referrer exist or not?
632		if($mybb->settings['usereferrals'] == 1 && !empty($user['referrer']))
633		{
634			$referrer = get_user_by_username($user['referrer']);
635
636			if(empty($referrer['uid']))
637			{
638				$this->set_error('invalid_referrer', array($user['referrer']));
639				return false;
640			}
641
642			$user['referrer_uid'] = $referrer['uid'];
643		}
644		else
645		{
646			$user['referrer_uid'] = 0;
647		}
648
649		return true;
650	}
651
652	/**
653	* Verifies user options.
654	*
655	* @return boolean True when valid, false when invalid.
656	*/
657	function verify_options()
658	{
659		global $mybb;
660
661		$options = &$this->data['options'];
662
663		if(!is_array($options))
664		{
665			$options = array();
666		}
667
668		// Verify yes/no options.
669		$this->verify_yesno_option($options, 'allownotices', 1);
670		$this->verify_yesno_option($options, 'hideemail', 0);
671		$this->verify_yesno_option($options, 'receivepms', 1);
672		$this->verify_yesno_option($options, 'receivefrombuddy', 0);
673		$this->verify_yesno_option($options, 'pmnotice', 1);
674		$this->verify_yesno_option($options, 'pmnotify', 1);
675		$this->verify_yesno_option($options, 'invisible', 0);
676		$this->verify_yesno_option($options, 'showimages', 1);
677		$this->verify_yesno_option($options, 'showvideos', 1);
678		$this->verify_yesno_option($options, 'showsigs', 1);
679		$this->verify_yesno_option($options, 'showavatars', 1);
680		$this->verify_yesno_option($options, 'showquickreply', 1);
681		$this->verify_yesno_option($options, 'showredirect', 1);
682		$this->verify_yesno_option($options, 'showcodebuttons', 1);
683		$this->verify_yesno_option($options, 'sourceeditor', 0);
684		$this->verify_yesno_option($options, 'buddyrequestspm', 1);
685		$this->verify_yesno_option($options, 'buddyrequestsauto', 0);
686
687		if($mybb->settings['postlayout'] == 'classic')
688		{
689			$this->verify_yesno_option($options, 'classicpostbit', 1);
690		}
691		else
692		{
693			$this->verify_yesno_option($options, 'classicpostbit', 0);
694		}
695
696		if(array_key_exists('subscriptionmethod', $options))
697		{
698			// Value out of range
699			$options['subscriptionmethod'] = (int)$options['subscriptionmethod'];
700			if($options['subscriptionmethod'] < 0 || $options['subscriptionmethod'] > 3)
701			{
702				$options['subscriptionmethod'] = 0;
703			}
704		}
705
706		if(array_key_exists('dstcorrection', $options))
707		{
708			// Value out of range
709			$options['dstcorrection'] = (int)$options['dstcorrection'];
710			if($options['dstcorrection'] < 0 || $options['dstcorrection'] > 2)
711			{
712				$options['dstcorrection'] = 0;
713			}
714
715			if($options['dstcorrection'] == 1)
716			{
717				$options['dst'] = 1;
718			}
719			elseif($options['dstcorrection'] == 0)
720			{
721				$options['dst'] = 0;
722			}
723		}
724
725		if($this->method == "insert" || (isset($options['threadmode']) && $options['threadmode'] != "linear" && $options['threadmode'] != "threaded" && $options['threadmode'] != ''))
726		{
727			$options['threadmode'] = '';
728		}
729
730		// Verify the "threads per page" option.
731		if($this->method == "insert" || (array_key_exists('tpp', $options) && $mybb->settings['usertppoptions']))
732		{
733			if(!isset($options['tpp']))
734			{
735				$options['tpp'] = 0;
736			}
737			$explodedtpp = explode(",", $mybb->settings['usertppoptions']);
738			if(is_array($explodedtpp))
739			{
740				@asort($explodedtpp);
741				$biggest = $explodedtpp[count($explodedtpp)-1];
742				// Is the selected option greater than the allowed options?
743				if($options['tpp'] > $biggest)
744				{
745					$options['tpp'] = $biggest;
746				}
747			}
748			$options['tpp'] = (int)$options['tpp'];
749		}
750		// Verify the "posts per page" option.
751		if($this->method == "insert" || (array_key_exists('ppp', $options) && $mybb->settings['userpppoptions']))
752		{
753			if(!isset($options['ppp']))
754			{
755				$options['ppp'] = 0;
756			}
757			$explodedppp = explode(",", $mybb->settings['userpppoptions']);
758			if(is_array($explodedppp))
759			{
760				@asort($explodedppp);
761				$biggest = $explodedppp[count($explodedppp)-1];
762				// Is the selected option greater than the allowed options?
763				if($options['ppp'] > $biggest)
764				{
765					$options['ppp'] = $biggest;
766				}
767			}
768			$options['ppp'] = (int)$options['ppp'];
769		}
770		// Is our selected "days prune" option valid or not?
771		if($this->method == "insert" || array_key_exists('daysprune', $options))
772		{
773			if(!isset($options['daysprune']))
774			{
775				$options['daysprune'] = 0;
776			}
777			$options['daysprune'] = (int)$options['daysprune'];
778			if($options['daysprune'] < 0)
779			{
780				$options['daysprune'] = 0;
781			}
782		}
783		$this->data['options'] = $options;
784	}
785
786	/**
787	 * Verifies if a registration date is valid or not.
788	 *
789	 * @return boolean True when valid, false when invalid.
790	 */
791	function verify_regdate()
792	{
793		$regdate = &$this->data['regdate'];
794
795		$regdate = (int)$regdate;
796		// If the timestamp is below 0, set it to the current time.
797		if($regdate <= 0)
798		{
799			$regdate = TIME_NOW;
800		}
801		return true;
802	}
803
804	/**
805	 * Verifies if a last visit date is valid or not.
806	 *
807	 * @return boolean True when valid, false when invalid.
808	 */
809	function verify_lastvisit()
810	{
811		$lastvisit = &$this->data['lastvisit'];
812
813		$lastvisit = (int)$lastvisit;
814		// If the timestamp is below 0, set it to the current time.
815		if($lastvisit <= 0)
816		{
817			$lastvisit = TIME_NOW;
818		}
819		return true;
820
821	}
822
823	/**
824	 * Verifies if a last active date is valid or not.
825	 *
826	 * @return boolean True when valid, false when invalid.
827	 */
828	function verify_lastactive()
829	{
830		$lastactive = &$this->data['lastactive'];
831
832		$lastactive = (int)$lastactive;
833		// If the timestamp is below 0, set it to the current time.
834		if($lastactive <= 0)
835		{
836			$lastactive = TIME_NOW;
837		}
838		return true;
839
840	}
841
842	/**
843	 * Verifies if an away mode status is valid or not.
844	 *
845	 * @return boolean True when valid, false when invalid.
846	 */
847	function verify_away()
848	{
849		global $mybb;
850
851		$user = &$this->data;
852		// If the board does not allow "away mode" or the user is marking as not away, set defaults.
853		if($mybb->settings['allowaway'] == 0 || !isset($user['away']['away']) || $user['away']['away'] != 1)
854		{
855			$user['away']['away'] = 0;
856			$user['away']['date'] = 0;
857			$user['away']['returndate'] = 0;
858			$user['away']['awayreason'] = '';
859			return true;
860		}
861		elseif($user['away']['returndate'])
862		{
863			// Validate the awayreason length, since the db holds 200 chars for this field
864			$reasonlength = my_strlen($user['away']['awayreason']);
865			if($reasonlength > 200)
866			{
867				$this->set_error("away_too_long", array($reasonlength - 200));
868				return false;
869			}
870
871			list($returnday, $returnmonth, $returnyear) = explode('-', $user['away']['returndate']);
872			if(!$returnday || !$returnmonth || !$returnyear)
873			{
874				$this->set_error("missing_returndate");
875				return false;
876			}
877
878			// Validate the return date lengths
879			$user['away']['returndate'] = substr($returnday, 0, 2).'-'.substr($returnmonth, 0, 2).'-'.substr($returnyear, 0, 4);
880		}
881		return true;
882	}
883
884	/**
885	 * Verifies if a language is valid for this user or not.
886	 *
887	 * @return boolean True when valid, false when invalid.
888	 */
889	function verify_language()
890	{
891		global $lang;
892
893		$language = &$this->data['language'];
894
895		// An invalid language has been specified?
896		if($language != '' && !$lang->language_exists($language))
897		{
898			$this->set_error("invalid_language");
899			return false;
900		}
901		return true;
902	}
903
904	/**
905	 * Verifies if a style is valid for this user or not.
906	 *
907	 * @return boolean True when valid, false when invalid.
908	 */
909	function verify_style()
910	{
911		global $lang;
912
913		$user = &$this->data;
914
915		if(!empty($user['style']))
916		{
917			$theme = get_theme($user['style']);
918
919			if(empty($theme) || !is_member($theme['allowedgroups'], $user) && $theme['allowedgroups'] != 'all')
920			{
921				$this->set_error('invalid_style');
922				return false;
923			}
924		}
925
926		return true;
927	}
928
929	/**
930	 * Verifies if this is coming from a spam bot or not
931	 *
932	 * @return boolean True when valid, false when invalid.
933	 */
934	function verify_checkfields()
935	{
936		$user = &$this->data;
937
938		// An invalid language has been specified?
939		if($user['regcheck1'] !== "" || $user['regcheck2'] !== "true")
940		{
941			$this->set_error("invalid_checkfield");
942			return false;
943		}
944		return true;
945	}
946
947	/**
948	 * Verifies if the user timezone is valid.
949	 * If the timezone is invalid, the board default is used.
950	 *
951	 * @return boolean True when timezone was valid, false otherwise
952	 */
953	function verify_timezone()
954	{
955		global $mybb;
956
957		$user = &$this->data;
958
959		$timezones = get_supported_timezones();
960
961		if(!isset($user['timezone']) || !array_key_exists($user['timezone'], $timezones))
962		{
963			$user['timezone'] = $mybb->settings['timezoneoffset'];
964			return false;
965		}
966
967		return true;
968	}
969
970	/**
971	* Validate all user assets.
972	*
973	* @return boolean True when valid, false when invalid.
974	*/
975	function validate_user()
976	{
977		global $mybb, $plugins;
978
979		$user = &$this->data;
980
981		// First, grab the old user details if this user exists
982		if(!empty($user['uid']))
983		{
984			$old_user = get_user($user['uid']);
985		}
986
987		if($this->method == "insert" || array_key_exists('username', $user))
988		{
989			// If the username is the same - no need to verify
990			if(!isset($old_user['username']) || $user['username'] != $old_user['username'])
991			{
992				$this->verify_username();
993				$this->verify_username_exists();
994			}
995			else
996			{
997				unset($user['username']);
998			}
999		}
1000		if($this->method == "insert" || array_key_exists('usertitle', $user))
1001		{
1002			$this->verify_usertitle();
1003		}
1004		if($this->method == "insert" || array_key_exists('password', $user))
1005		{
1006			$this->verify_password();
1007		}
1008		if($this->method == "insert" || array_key_exists('usergroup', $user))
1009		{
1010			$this->verify_usergroup();
1011		}
1012		if($this->method == "insert" || array_key_exists('email', $user))
1013		{
1014			$this->verify_email();
1015		}
1016		if($this->method == "insert" || array_key_exists('website', $user))
1017		{
1018			$this->verify_website();
1019		}
1020		if($this->method == "insert" || array_key_exists('icq', $user))
1021		{
1022			$this->verify_icq();
1023		}
1024		if($this->method == "insert" || (isset($user['birthday']) && is_array($user['birthday'])))
1025		{
1026			$this->verify_birthday();
1027		}
1028		if($this->method == "insert" || array_key_exists('postnum', $user))
1029		{
1030			$this->verify_postnum();
1031		}
1032		if($this->method == "insert" || array_key_exists('threadnum', $user))
1033		{
1034			$this->verify_threadnum();
1035		}
1036		if($this->method == "insert" || array_key_exists('profile_fields', $user))
1037		{
1038			$this->verify_profile_fields();
1039		}
1040		if($this->method == "insert" || array_key_exists('referrer', $user))
1041		{
1042			$this->verify_referrer();
1043		}
1044		if($this->method == "insert" || array_key_exists('options', $user))
1045		{
1046			$this->verify_options();
1047		}
1048		if($this->method == "insert" || array_key_exists('regdate', $user))
1049		{
1050			$this->verify_regdate();
1051		}
1052		if($this->method == "insert" || array_key_exists('lastvisit', $user))
1053		{
1054			$this->verify_lastvisit();
1055		}
1056		if($this->method == "insert" || array_key_exists('lastactive', $user))
1057		{
1058			$this->verify_lastactive();
1059		}
1060		if($this->method == "insert" || array_key_exists('away', $user))
1061		{
1062			$this->verify_away();
1063		}
1064		if($this->method == "insert" || array_key_exists('language', $user))
1065		{
1066			$this->verify_language();
1067		}
1068		if($this->method == "insert" || array_key_exists('timezone', $user))
1069		{
1070			$this->verify_timezone();
1071		}
1072		if($this->method == "insert" && array_key_exists('regcheck1', $user) && array_key_exists('regcheck2', $user))
1073		{
1074			$this->verify_checkfields();
1075		}
1076		if(array_key_exists('birthdayprivacy', $user))
1077		{
1078			$this->verify_birthday_privacy();
1079		}
1080		if($this->method == "insert" || array_key_exists('style', $user))
1081		{
1082			$this->verify_style();
1083		}
1084		if($this->method == "insert" || array_key_exists('signature', $user))
1085		{
1086			$this->verify_signature();
1087		}
1088
1089		$plugins->run_hooks("datahandler_user_validate", $this);
1090
1091		// We are done validating, return.
1092		$this->set_validated(true);
1093		if(count($this->get_errors()) > 0)
1094		{
1095			return false;
1096		}
1097		else
1098		{
1099			return true;
1100		}
1101	}
1102
1103	/**
1104	* Inserts a user into the database.
1105	*
1106	* @return array
1107	*/
1108	function insert_user()
1109	{
1110		global $db, $cache, $plugins;
1111
1112		// Yes, validating is required.
1113		if(!$this->get_validated())
1114		{
1115			die("The user needs to be validated before inserting it into the DB.");
1116		}
1117		if(count($this->get_errors()) > 0)
1118		{
1119			die("The user is not valid.");
1120		}
1121
1122		$user = &$this->data;
1123
1124		$array = array('postnum', 'threadnum', 'avatar', 'avatartype', 'additionalgroups', 'displaygroup', 'icq', 'skype', 'google', 'bday', 'signature', 'style', 'dateformat', 'timeformat', 'notepad', 'regip', 'lastip', 'coppa_user');
1125		foreach($array as $value)
1126		{
1127			if(!isset($user[$value]))
1128			{
1129				$user[$value] = '';
1130			}
1131		}
1132
1133		$array = array('subscriptionmethod', 'dstcorrection');
1134		foreach($array as $value)
1135		{
1136			if(!isset($user['options'][$value]))
1137			{
1138				$user['options'][$value] = '';
1139			}
1140		}
1141
1142		// If user is being created from ACP, there is no last visit or last active
1143		if(defined('IN_ADMINCP'))
1144		{
1145			$user['lastvisit'] = $user['lastactive'] = 0;
1146		}
1147
1148		$this->user_insert_data = array(
1149			"username" => $db->escape_string($user['username']),
1150			"password" => $user['password'],
1151			"salt" => $user['salt'],
1152			"loginkey" => $user['loginkey'],
1153			"email" => $db->escape_string($user['email']),
1154			"postnum" => (int)$user['postnum'],
1155			"threadnum" => (int)$user['threadnum'],
1156			"avatar" => $db->escape_string($user['avatar']),
1157			"avatartype" => $db->escape_string($user['avatartype']),
1158			"usergroup" => (int)$user['usergroup'],
1159			"additionalgroups" => $db->escape_string($user['additionalgroups']),
1160			"displaygroup" => (int)$user['displaygroup'],
1161			"usertitle" => $db->escape_string(htmlspecialchars_uni($user['usertitle'])),
1162			"regdate" => (int)$user['regdate'],
1163			"lastactive" => (int)$user['lastactive'],
1164			"lastvisit" => (int)$user['lastvisit'],
1165			"website" => $db->escape_string($user['website']),
1166			"icq" => (int)$user['icq'],
1167			"skype" => $db->escape_string($user['skype']),
1168			"google" => $db->escape_string($user['google']),
1169			"birthday" => $user['bday'],
1170			"signature" => $db->escape_string($user['signature']),
1171			"allownotices" => (int)$user['options']['allownotices'],
1172			"hideemail" => (int)$user['options']['hideemail'],
1173			"subscriptionmethod" => (int)$user['options']['subscriptionmethod'],
1174			"receivepms" => (int)$user['options']['receivepms'],
1175			"receivefrombuddy" => (int)$user['options']['receivefrombuddy'],
1176			"pmnotice" => (int)$user['options']['pmnotice'],
1177			"pmnotify" => (int)$user['options']['pmnotify'],
1178			"showimages" => (int)$user['options']['showimages'],
1179			"showvideos" => (int)$user['options']['showvideos'],
1180			"showsigs" => (int)$user['options']['showsigs'],
1181			"showavatars" => (int)$user['options']['showavatars'],
1182			"showquickreply" => (int)$user['options']['showquickreply'],
1183			"showredirect" => (int)$user['options']['showredirect'],
1184			"tpp" => (int)$user['options']['tpp'],
1185			"ppp" => (int)$user['options']['ppp'],
1186			"invisible" => (int)$user['options']['invisible'],
1187			"style" => (int)$user['style'],
1188			"timezone" => $db->escape_string($user['timezone']),
1189			"dstcorrection" => (int)$user['options']['dstcorrection'],
1190			"threadmode" => $user['options']['threadmode'],
1191			"daysprune" => (int)$user['options']['daysprune'],
1192			"dateformat" => $db->escape_string($user['dateformat']),
1193			"timeformat" => $db->escape_string($user['timeformat']),
1194			"regip" => $db->escape_binary($user['regip']),
1195			"lastip" => $db->escape_binary($user['lastip']),
1196			"language" => $db->escape_string($user['language']),
1197			"showcodebuttons" => (int)$user['options']['showcodebuttons'],
1198			"sourceeditor" => (int)$user['options']['sourceeditor'],
1199			"buddyrequestspm" => (int)$user['options']['buddyrequestspm'],
1200			"buddyrequestsauto" => (int)$user['options']['buddyrequestsauto'],
1201			"away" => (int)$user['away']['away'],
1202			"awaydate" => (int)$user['away']['date'],
1203			"returndate" => $user['away']['returndate'],
1204			"awayreason" => $db->escape_string($user['away']['awayreason']),
1205			"referrer" => (int)$user['referrer_uid'],
1206			"referrals" => 0,
1207			"buddylist" => '',
1208			"ignorelist" => '',
1209			"pmfolders" => "0**$%%$1**$%%$2**$%%$3**$%%$4**",
1210			"notepad" => '',
1211			"warningpoints" => 0,
1212			"moderateposts" => 0,
1213			"moderationtime" => 0,
1214			"suspendposting" => 0,
1215			"suspensiontime" => 0,
1216			"coppauser" => (int)$user['coppa_user'],
1217			"classicpostbit" => (int)$user['options']['classicpostbit'],
1218			"usernotes" => ''
1219		);
1220
1221		if($user['options']['dstcorrection'] == 1)
1222		{
1223			$this->user_insert_data['dst'] = 1;
1224		}
1225		elseif($user['options']['dstcorrection'] == 0)
1226		{
1227			$this->user_insert_data['dst'] = 0;
1228		}
1229
1230		$plugins->run_hooks("datahandler_user_insert", $this);
1231
1232		$this->uid = $db->insert_query("users", $this->user_insert_data);
1233
1234		$user['user_fields']['ufid'] = $this->uid;
1235
1236		$pfcache = $cache->read('profilefields');
1237
1238		if(is_array($pfcache))
1239		{
1240			foreach($pfcache as $profile_field)
1241			{
1242				if(array_key_exists("fid{$profile_field['fid']}", $user['user_fields']))
1243				{
1244					continue;
1245				}
1246				$user['user_fields']["fid{$profile_field['fid']}"] = '';
1247			}
1248		}
1249
1250		$db->insert_query("userfields", $user['user_fields'], false);
1251
1252		if($this->user_insert_data['referrer'] != 0)
1253		{
1254			$db->write_query("
1255				UPDATE ".TABLE_PREFIX."users
1256				SET referrals=referrals+1
1257				WHERE uid='{$this->user_insert_data['referrer']}'
1258			");
1259		}
1260
1261		// Update forum stats
1262		update_stats(array('numusers' => '+1'));
1263
1264		if((int)$user['usergroup'] == 5)
1265		{
1266			$cache->update_awaitingactivation();
1267		}
1268
1269		$this->return_values = array(
1270			"uid" => $this->uid,
1271			"username" => $user['username'],
1272			"loginkey" => $user['loginkey'],
1273			"email" => $user['email'],
1274			"password" => $user['password'],
1275			"usergroup" => $user['usergroup']
1276		);
1277
1278		$plugins->run_hooks("datahandler_user_insert_end", $this);
1279
1280		return $this->return_values;
1281	}
1282
1283	/**
1284	* Updates a user in the database.
1285	*
1286	* @return bool
1287	*/
1288	function update_user()
1289	{
1290		global $db, $plugins, $cache;
1291
1292		// Yes, validating is required.
1293		if(!$this->get_validated())
1294		{
1295			die("The user needs to be validated before inserting it into the DB.");
1296		}
1297		if(count($this->get_errors()) > 0)
1298		{
1299			die("The user is not valid.");
1300		}
1301
1302		$user = &$this->data;
1303		$user['uid'] = (int)$user['uid'];
1304		$this->uid = $user['uid'];
1305
1306		// Set up the update data.
1307		if(isset($user['username']))
1308		{
1309			$this->user_update_data['username'] = $db->escape_string($user['username']);
1310		}
1311		if(isset($user['password']))
1312		{
1313			$this->user_update_data['password'] = $user['password'];
1314		}
1315		if(isset($user['salt']))
1316		{
1317			$this->user_update_data['salt'] = $user['salt'];
1318		}
1319		if(isset($user['loginkey']))
1320		{
1321			$this->user_update_data['loginkey'] = $user['loginkey'];
1322		}
1323		if(isset($user['email']))
1324		{
1325			$this->user_update_data['email'] = $db->escape_string($user['email']);
1326		}
1327		if(isset($user['postnum']))
1328		{
1329			$this->user_update_data['postnum'] = (int)$user['postnum'];
1330		}
1331		if(isset($user['threadnum']))
1332		{
1333			$this->user_update_data['threadnum'] = (int)$user['threadnum'];
1334		}
1335		if(isset($user['avatar']))
1336		{
1337			$this->user_update_data['avatar'] = $db->escape_string($user['avatar']);
1338			$this->user_update_data['avatartype'] = $db->escape_string($user['avatartype']);
1339		}
1340		if(isset($user['usergroup']))
1341		{
1342			$this->user_update_data['usergroup'] = (int)$user['usergroup'];
1343		}
1344		if(isset($user['additionalgroups']))
1345		{
1346			$this->user_update_data['additionalgroups'] = $db->escape_string($user['additionalgroups']);
1347		}
1348		if(isset($user['displaygroup']))
1349		{
1350			$this->user_update_data['displaygroup'] = (int)$user['displaygroup'];
1351		}
1352		if(isset($user['usertitle']))
1353		{
1354			$this->user_update_data['usertitle'] = $db->escape_string($user['usertitle']);
1355		}
1356		if(isset($user['regdate']))
1357		{
1358			$this->user_update_data['regdate'] = (int)$user['regdate'];
1359		}
1360		if(isset($user['lastactive']))
1361		{
1362			$this->user_update_data['lastactive'] = (int)$user['lastactive'];
1363		}
1364		if(isset($user['lastvisit']))
1365		{
1366			$this->user_update_data['lastvisit'] = (int)$user['lastvisit'];
1367		}
1368		if(isset($user['signature']))
1369		{
1370			$this->user_update_data['signature'] = $db->escape_string($user['signature']);
1371		}
1372		if(isset($user['website']))
1373		{
1374			$this->user_update_data['website'] = $db->escape_string($user['website']);
1375		}
1376		if(isset($user['icq']))
1377		{
1378			$this->user_update_data['icq'] = (int)$user['icq'];
1379		}
1380		if(isset($user['skype']))
1381		{
1382			$this->user_update_data['skype'] = $db->escape_string($user['skype']);
1383		}
1384		if(isset($user['google']))
1385		{
1386			$this->user_update_data['google'] = $db->escape_string($user['google']);
1387		}
1388		if(isset($user['bday']))
1389		{
1390			$this->user_update_data['birthday'] = $user['bday'];
1391		}
1392		if(isset($user['birthdayprivacy']))
1393		{
1394			$this->user_update_data['birthdayprivacy'] = $db->escape_string($user['birthdayprivacy']);
1395		}
1396		if(isset($user['style']))
1397		{
1398			$this->user_update_data['style'] = (int)$user['style'];
1399		}
1400		if(isset($user['timezone']))
1401		{
1402			$this->user_update_data['timezone'] = $db->escape_string($user['timezone']);
1403		}
1404		if(isset($user['dateformat']))
1405		{
1406			$this->user_update_data['dateformat'] = $db->escape_string($user['dateformat']);
1407		}
1408		if(isset($user['timeformat']))
1409		{
1410			$this->user_update_data['timeformat'] = $db->escape_string($user['timeformat']);
1411		}
1412		if(isset($user['regip']))
1413		{
1414			$this->user_update_data['regip'] = $db->escape_string($user['regip']);
1415		}
1416		if(isset($user['lastip']))
1417		{
1418			$this->user_update_data['lastip'] = $db->escape_string($user['lastip']);
1419		}
1420		if(isset($user['language']))
1421		{
1422			$this->user_update_data['language'] = $db->escape_string($user['language']);
1423		}
1424		if(isset($user['away']))
1425		{
1426			$this->user_update_data['away'] = (int)$user['away']['away'];
1427			$this->user_update_data['awaydate'] = $db->escape_string($user['away']['date']);
1428			$this->user_update_data['returndate'] = $db->escape_string($user['away']['returndate']);
1429			$this->user_update_data['awayreason'] = $db->escape_string($user['away']['awayreason']);
1430		}
1431		if(isset($user['notepad']))
1432		{
1433			$this->user_update_data['notepad'] = $db->escape_string($user['notepad']);
1434		}
1435		if(isset($user['usernotes']))
1436		{
1437			$this->user_update_data['usernotes'] = $db->escape_string($user['usernotes']);
1438		}
1439		if(isset($user['options']) && is_array($user['options']))
1440		{
1441			foreach($user['options'] as $option => $value)
1442			{
1443				$this->user_update_data[$option] = $value;
1444			}
1445		}
1446		if(array_key_exists('coppa_user', $user))
1447		{
1448			$this->user_update_data['coppauser'] = (int)$user['coppa_user'];
1449		}
1450		// First, grab the old user details for later use.
1451		$old_user = get_user($user['uid']);
1452
1453		// If old user has new pmnotice and new user has = yes, keep old value
1454		if($old_user['pmnotice'] == "2" && $this->user_update_data['pmnotice'] == 1)
1455		{
1456			unset($this->user_update_data['pmnotice']);
1457		}
1458
1459		$plugins->run_hooks("datahandler_user_update", $this);
1460
1461		if(count($this->user_update_data) < 1 && empty($user['user_fields']))
1462		{
1463			return false;
1464		}
1465
1466		if(count($this->user_update_data) > 0)
1467		{
1468			// Actual updating happens here.
1469			$db->update_query("users", $this->user_update_data, "uid='{$user['uid']}'");
1470		}
1471
1472		$cache->update_moderators();
1473		if(isset($user['bday']) || isset($user['username']))
1474		{
1475			$cache->update_birthdays();
1476		}
1477
1478		if(isset($user['usergroup']) && (int)$user['usergroup'] == 5)
1479		{
1480			$cache->update_awaitingactivation();
1481		}
1482
1483		// Maybe some userfields need to be updated?
1484		if(isset($user['user_fields']) && is_array($user['user_fields']))
1485		{
1486			$query = $db->simple_select("userfields", "*", "ufid='{$user['uid']}'");
1487			$fields = $db->fetch_array($query);
1488			if(empty($fields['ufid']))
1489			{
1490				$user_fields = array(
1491					'ufid' => $user['uid']
1492				);
1493
1494				$fields_array = $db->show_fields_from("userfields");
1495				foreach($fields_array as $field)
1496				{
1497					if($field['Field'] == 'ufid')
1498					{
1499						continue;
1500					}
1501					$user_fields[$field['Field']] = '';
1502				}
1503				$db->insert_query("userfields", $user_fields);
1504			}
1505			$db->update_query("userfields", $user['user_fields'], "ufid='{$user['uid']}'", false);
1506		}
1507
1508		// Let's make sure the user's name gets changed everywhere in the db if it changed.
1509		if(!empty($this->user_update_data['username']) && $this->user_update_data['username'] != $old_user['username'])
1510		{
1511			$username_update = array(
1512				"username" => $this->user_update_data['username']
1513			);
1514			$lastposter_update = array(
1515				"lastposter" => $this->user_update_data['username']
1516			);
1517
1518			$db->update_query("posts", $username_update, "uid='{$user['uid']}'");
1519			$db->update_query("threads", $username_update, "uid='{$user['uid']}'");
1520			$db->update_query("threads", $lastposter_update, "lastposteruid='{$user['uid']}'");
1521			$db->update_query("forums", $lastposter_update, "lastposteruid='{$user['uid']}'");
1522
1523			$stats = $cache->read("stats");
1524			if($stats['lastuid'] == $user['uid'])
1525			{
1526				// User was latest to register, update stats
1527				update_stats(array("numusers" => "+0"));
1528			}
1529		}
1530
1531		return true;
1532	}
1533
1534	/**
1535	 * Provides a method to completely delete a user.
1536	 *
1537	 * @param array $delete_uids Array of user information
1538	 * @param integer $prunecontent Whether if delete threads/posts or not
1539	 * @return array
1540	 */
1541	function delete_user($delete_uids, $prunecontent=0)
1542	{
1543		global $db, $plugins, $mybb, $cache;
1544
1545		// Yes, validating is required.
1546		if(count($this->get_errors()) > 0)
1547		{
1548			die('The user is not valid.');
1549		}
1550
1551		$this->delete_uids = array_map('intval', (array)$delete_uids);
1552
1553		foreach($this->delete_uids as $key => $uid)
1554		{
1555			if(!$uid || is_super_admin($uid) || $uid == $mybb->user['uid'])
1556			{
1557				// Remove super admins
1558				unset($this->delete_uids[$key]);
1559			}
1560		}
1561
1562		$plugins->run_hooks('datahandler_user_delete_start', $this);
1563
1564		$this->delete_uids = implode(',', $this->delete_uids);
1565
1566		if(empty($this->delete_uids))
1567		{
1568			$this->deleted_users = 0;
1569			$this->return_values = array(
1570				"deleted_users" => $this->deleted_users
1571			);
1572
1573			return $this->return_values;
1574		}
1575
1576		$this->delete_content();
1577
1578		// Delete the user
1579		$query = $db->delete_query('users', "uid IN({$this->delete_uids})");
1580		$this->deleted_users = $db->affected_rows($query);
1581
1582		// Are we removing the posts/threads of a user?
1583		if((int)$prunecontent == 1)
1584		{
1585			$this->delete_posts();
1586			$db->delete_query('announcements', "uid IN({$this->delete_uids})");
1587		}
1588		else
1589		{
1590			// We're just updating the UID
1591			$db->update_query('pollvotes', array('uid' => 0), "uid IN({$this->delete_uids})");
1592			$db->update_query('posts', array('uid' => 0), "uid IN({$this->delete_uids})");
1593			$db->update_query('threads', array('uid' => 0), "uid IN({$this->delete_uids})");
1594			$db->update_query('attachments', array('uid' => 0), "uid IN({$this->delete_uids})");
1595			$db->update_query('announcements', array('uid' => 0), "uid IN({$this->delete_uids})");
1596		}
1597
1598		$db->update_query('privatemessages', array('fromid' => 0), "fromid IN({$this->delete_uids})");
1599		$db->update_query('users', array('referrer' => 0), "referrer IN({$this->delete_uids})");
1600
1601		// Update thread ratings
1602		$query = $db->query("
1603			SELECT r.*, t.numratings, t.totalratings
1604			FROM ".TABLE_PREFIX."threadratings r
1605			LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=r.tid)
1606			WHERE r.uid IN({$this->delete_uids})
1607		");
1608		while($rating = $db->fetch_array($query))
1609		{
1610			$update_thread = array(
1611				"numratings" => $rating['numratings'] - 1,
1612				"totalratings" => $rating['totalratings'] - $rating['rating']
1613			);
1614			$db->update_query("threads", $update_thread, "tid='{$rating['tid']}'");
1615		}
1616
1617		$db->delete_query('threadratings', "uid IN({$this->delete_uids})");
1618
1619		// Update forums & threads if user is the lastposter
1620		$db->update_query('forums', array('lastposteruid' => 0), "lastposteruid IN({$this->delete_uids})");
1621		$db->update_query('threads', array('lastposteruid' => 0), "lastposteruid IN({$this->delete_uids})");
1622
1623		// Update forum stats
1624		update_stats(array('numusers' => '-'.$this->deleted_users));
1625
1626		$this->return_values = array(
1627			"deleted_users" => $this->deleted_users
1628		);
1629
1630		$plugins->run_hooks("datahandler_user_delete_end", $this);
1631
1632		// Update  cache
1633		$cache->update_moderators();
1634		$cache->update_forumsdisplay();
1635		$cache->update_reportedcontent();
1636		$cache->update_awaitingactivation();
1637		$cache->update_birthdays();
1638
1639		return $this->return_values;
1640	}
1641
1642	/**
1643	 * Provides a method to delete users' content
1644	 *
1645	 * @param array|bool $delete_uids Array of user ids, false if they're already set (eg when using the delete_user function)
1646	 */
1647	function delete_content($delete_uids=false)
1648	{
1649		global $db, $plugins, $mybb;
1650
1651		if($delete_uids != false)
1652		{
1653			$this->delete_uids = array_map('intval', (array)$delete_uids);
1654
1655			foreach($this->delete_uids as $key => $uid)
1656			{
1657				if(!$uid || is_super_admin($uid) || $uid == $mybb->user['uid'])
1658				{
1659					// Remove super admins
1660					unset($this->delete_uids[$key]);
1661				}
1662			}
1663
1664			$this->delete_uids = implode(',', $this->delete_uids);
1665		}
1666
1667		$plugins->run_hooks('datahandler_user_delete_content', $this);
1668
1669		if(empty($this->delete_uids))
1670		{
1671			return;
1672		}
1673
1674		$db->delete_query('userfields', "ufid IN({$this->delete_uids})");
1675		$db->delete_query('privatemessages', "uid IN({$this->delete_uids})");
1676		$db->delete_query('events', "uid IN({$this->delete_uids})");
1677		$db->delete_query('moderators', "id IN({$this->delete_uids}) AND isgroup = 0");
1678		$db->delete_query('forumsubscriptions', "uid IN({$this->delete_uids})");
1679		$db->delete_query('threadsubscriptions', "uid IN({$this->delete_uids})");
1680		$db->delete_query('forumsread', "uid IN({$this->delete_uids})");
1681		$db->delete_query('threadsread', "uid IN({$this->delete_uids})");
1682		$db->delete_query('adminviews', "uid IN({$this->delete_uids})");
1683		$db->delete_query('adminoptions', "uid IN({$this->delete_uids})");
1684		$db->delete_query('adminsessions', "uid IN({$this->delete_uids})");
1685		$db->delete_query('sessions', "uid IN({$this->delete_uids})");
1686		$db->delete_query('banned', "uid IN({$this->delete_uids})");
1687		$db->delete_query('joinrequests', "uid IN({$this->delete_uids})");
1688		$db->delete_query('groupleaders', "uid IN({$this->delete_uids})");
1689		$db->delete_query('awaitingactivation', "uid IN({$this->delete_uids})");
1690		$db->delete_query('warnings', "uid IN({$this->delete_uids})");
1691		$db->delete_query('reputation', "uid IN({$this->delete_uids}) OR adduid IN({$this->delete_uids})");
1692		$db->delete_query('buddyrequests', "uid IN({$this->delete_uids}) OR touid IN({$this->delete_uids})");
1693		$db->delete_query('posts', "uid IN({$this->delete_uids}) AND visible = -2");
1694		$db->delete_query('threads', "uid IN({$this->delete_uids}) AND visible = -2");
1695
1696		// Delete reports made to the profile or reputation of the deleted users (i.e. made by them)
1697		$db->delete_query('reportedcontent', "type='reputation' AND id3 IN({$this->delete_uids}) OR type='reputation' AND id2 IN({$this->delete_uids})");
1698		$db->delete_query('reportedcontent', "type='profile' AND id IN({$this->delete_uids})");
1699
1700		// Update the reports made by the deleted users by setting the uid to 0
1701		$db->update_query('reportedcontent', array('uid' => 0), "uid IN({$this->delete_uids})");
1702
1703		// Remove any of the user(s) uploaded avatars
1704		require_once MYBB_ROOT.'inc/functions_upload.php';
1705		foreach(explode(',', $this->delete_uids) as $uid)
1706		{
1707			remove_avatars($uid);
1708		}
1709	}
1710
1711	/**
1712	 * Provides a method to delete an users posts and threads
1713	 *
1714	 * @param array|bool $delete_uids Array of user ids, false if they're already set (eg when using the delete_user function)
1715	 */
1716	function delete_posts($delete_uids=false)
1717	{
1718		global $db, $plugins, $mybb;
1719
1720		if($delete_uids != false)
1721		{
1722			$this->delete_uids = array_map('intval', (array)$delete_uids);
1723
1724			foreach($this->delete_uids as $key => $uid)
1725			{
1726				if(!$uid || is_super_admin($uid) || $uid == $mybb->user['uid'])
1727				{
1728					// Remove super admins
1729					unset($this->delete_uids[$key]);
1730				}
1731			}
1732
1733			$this->delete_uids = implode(',', $this->delete_uids);
1734		}
1735
1736		require_once MYBB_ROOT.'inc/class_moderation.php';
1737		$moderation = new Moderation();
1738
1739		$plugins->run_hooks('datahandler_user_delete_posts', $this);
1740
1741		if(empty($this->delete_uids))
1742		{
1743			return;
1744		}
1745
1746		// Threads
1747		$query = $db->simple_select('threads', 'tid', "uid IN({$this->delete_uids})");
1748		while($tid = $db->fetch_field($query, 'tid'))
1749		{
1750			$moderation->delete_thread($tid);
1751		}
1752
1753		// Posts
1754		$query = $db->simple_select('posts', 'pid', "uid IN({$this->delete_uids})");
1755		while($pid = $db->fetch_field($query, 'pid'))
1756		{
1757			$moderation->delete_post($pid);
1758		}
1759	}
1760
1761	/**
1762	 * Provides a method to clear an users profile
1763	 *
1764	 * @param array|bool $delete_uids Array of user ids, false if they're already set (eg when using the delete_user function)
1765	 * @param int $gid The new usergroup if the users should be moved (additional usergroups are always removed)
1766	 */
1767	function clear_profile($delete_uids=false, $gid=0)
1768	{
1769		global $db, $plugins, $mybb;
1770
1771		// delete_uids isn't a nice name, but it's used as the functions above use the same
1772		if($delete_uids != false)
1773		{
1774			$this->delete_uids = array_map('intval', (array)$delete_uids);
1775
1776			foreach($this->delete_uids as $key => $uid)
1777			{
1778				if(!$uid || is_super_admin($uid) || $uid == $mybb->user['uid'])
1779				{
1780					// Remove super admins
1781					unset($this->delete_uids[$key]);
1782				}
1783			}
1784
1785			$this->delete_uids = implode(',', $this->delete_uids);
1786		}
1787
1788		$update = array(
1789			"website" => "",
1790			"birthday" => "",
1791			"icq" => "",
1792			"skype" => "",
1793			"google" => "",
1794			"usertitle" => "",
1795			"away" => 0,
1796			"awaydate" => 0,
1797			"returndate" => "",
1798			"awayreason" => "",
1799			"additionalgroups" => "",
1800			"displaygroup" => 0,
1801			"signature" => "",
1802			"avatar" => "",
1803			'avatardimensions' => '',
1804			'avatartype' => ''
1805		);
1806
1807		if($gid > 0)
1808		{
1809			$update["usergroup"] = (int)$gid;
1810		}
1811
1812		$plugins->run_hooks('datahandler_user_clear_profile', $this);
1813
1814		if(empty($this->delete_uids))
1815		{
1816			return;
1817		}
1818
1819		$db->update_query("users", $update, "uid IN({$this->delete_uids})");
1820		$db->delete_query('userfields', "ufid IN({$this->delete_uids})");
1821
1822		// Remove any of the user(s) uploaded avatars
1823		require_once MYBB_ROOT.'inc/functions_upload.php';
1824		foreach(explode(',', $this->delete_uids) as $uid)
1825		{
1826			remove_avatars($uid);
1827		}
1828	}
1829
1830	public function verify_signature()
1831	{
1832		global $mybb, $parser;
1833
1834		if(!isset($this->data['signature']))
1835		{
1836			return true;
1837		}
1838
1839		if(!isset($parser))
1840		{
1841			require_once MYBB_ROOT."inc/class_parser.php";
1842			$parser = new postParser;
1843		}
1844
1845		$parser_options = array(
1846			'allow_html' => $mybb->settings['sightml'],
1847			'allow_mycode' => $mybb->settings['sigmycode'],
1848			'allow_smilies' => $mybb->settings['sigsmilies'],
1849			'allow_imgcode' => $mybb->settings['sigimgcode'],
1850			"filter_badwords" => 1
1851		);
1852
1853		$parsed_sig = $parser->parse_message($this->data['signature'], $parser_options);
1854
1855		if((($mybb->settings['sigimgcode'] == 0 && $mybb->settings['sigsmilies'] != 1) &&
1856			substr_count($parsed_sig, "<img") > 0) ||
1857			(($mybb->settings['sigimgcode'] == 1 || $mybb->settings['sigsmilies'] == 1) &&
1858			substr_count($parsed_sig, "<img") > $mybb->settings['maxsigimages'])
1859		)
1860		{
1861			$imgsallowed = 0;
1862
1863			if($mybb->settings['sigimgcode'] == 1)
1864			{
1865				$imgsallowed = $mybb->settings['maxsigimages'];
1866			}
1867
1868			$this->set_error('too_many_sig_images2', array($imgsallowed));
1869		}
1870
1871		if($mybb->settings['sigcountmycode'] == 0)
1872		{
1873			$parsed_sig = $parser->text_parse_message($this->data['signature'], array('signature_parse' => '1'));
1874		}
1875		else
1876		{
1877			$parsed_sig = $this->data['signature'];
1878		}
1879
1880		if($mybb->settings['siglength'] > 0)
1881		{
1882			$parsed_sig = preg_replace("#\s#", "", $parsed_sig);
1883			$sig_length = my_strlen($parsed_sig);
1884
1885			if($sig_length > $mybb->settings['siglength'])
1886			{
1887				$this->set_error('sig_too_long', array($mybb->settings['siglength']));
1888
1889				if($sig_length - $mybb->settings['siglength'] > 1)
1890				{
1891					$this->set_error('sig_remove_chars_plural', array($sig_length-$mybb->settings['siglength']));
1892				}
1893				else
1894				{
1895					$this->set_error('sig_remove_chars_singular');
1896				}
1897			}
1898		}
1899
1900		if(count($this->get_errors()) > 0)
1901		{
1902			return false;
1903		}
1904		return true;
1905	}
1906}
1907