1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14namespace phpbb;
15
16/**
17* Base user class
18*
19* This is the overarching class which contains (through session extend)
20* all methods utilised for user functionality during a session.
21*/
22class user extends \phpbb\session
23{
24	/**
25	 * @var \phpbb\language\language
26	 */
27	protected $language;
28
29	var $style = array();
30	var $date_format;
31
32	/**
33	* DateTimeZone object holding the timezone of the user
34	*/
35	public $timezone;
36
37	/**
38	* @var string Class name of datetime object
39	*/
40	protected $datetime;
41
42	var $lang_name = false;
43	var $lang_id = false;
44	var $lang_path;
45	var $img_lang;
46	var $img_array = array();
47
48	/** @var bool */
49	protected $is_setup_flag;
50
51	// Able to add new options (up to id 31)
52	var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'sig_bbcode' => 15, 'sig_smilies' => 16, 'sig_links' => 17);
53
54	/**
55	* Constructor to set the lang path
56	*
57	* @param \phpbb\language\language	$lang			phpBB's Language loader
58	* @param string						$datetime_class	Class name of datetime class
59	*/
60	function __construct(\phpbb\language\language $lang, $datetime_class)
61	{
62		global $phpbb_root_path;
63
64		$this->lang_path = $phpbb_root_path . 'language/';
65		$this->language = $lang;
66		$this->datetime = $datetime_class;
67
68		$this->is_setup_flag = false;
69	}
70
71	/**
72	 * Returns whether user::setup was called
73	 *
74	 * @return bool
75	 */
76	public function is_setup()
77	{
78		return $this->is_setup_flag;
79	}
80
81	/**
82	 * Magic getter for BC compatibility
83	 *
84	 * Implement array access for user::lang.
85	 *
86	 * @param string	$param_name	Name of the BC component the user want to access
87	 *
88	 * @return array	The appropriate array
89	 *
90	 * @deprecated 3.2.0-dev (To be removed: 4.0.0)
91	 */
92	public function __get($param_name)
93	{
94		if ($param_name === 'lang')
95		{
96			return $this->language->get_lang_array();
97		}
98		else if ($param_name === 'help')
99		{
100			$help_array = $this->language->get_lang_array();
101			return $help_array['__help'];
102		}
103
104		return array();
105	}
106
107	/**
108	* Setup basic user-specific items (style, language, ...)
109	*/
110	function setup($lang_set = false, $style_id = false)
111	{
112		global $db, $request, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache;
113		global $phpbb_dispatcher, $phpbb_container;
114
115		$this->language->set_default_language($config['default_lang']);
116
117		if ($this->data['user_id'] != ANONYMOUS)
118		{
119			$user_lang_name = (file_exists($this->lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']);
120			$user_date_format = $this->data['user_dateformat'];
121			$user_timezone = $this->data['user_timezone'];
122		}
123		else
124		{
125			$lang_override = $request->variable('language', '');
126			if ($lang_override)
127			{
128				$this->set_cookie('lang', $lang_override, 0, false);
129			}
130			else
131			{
132				$lang_override = $request->variable($config['cookie_name'] . '_lang', '', true, \phpbb\request\request_interface::COOKIE);
133			}
134
135			if ($lang_override)
136			{
137				$use_lang = basename($lang_override);
138				$user_lang_name = (file_exists($this->lang_path . $use_lang . "/common.$phpEx")) ? $use_lang : basename($config['default_lang']);
139				$this->data['user_lang'] = $user_lang_name;
140			}
141			else
142			{
143				$user_lang_name = basename($config['default_lang']);
144			}
145
146			$user_date_format = $config['default_dateformat'];
147			$user_timezone = $config['board_timezone'];
148
149			/**
150			* If a guest user is surfing, we try to guess his/her language first by obtaining the browser language
151			* If re-enabled we need to make sure only those languages installed are checked
152			* Commented out so we do not loose the code.
153
154			if ($request->header('Accept-Language'))
155			{
156				$accept_lang_ary = explode(',', $request->header('Accept-Language'));
157
158				foreach ($accept_lang_ary as $accept_lang)
159				{
160					// Set correct format ... guess full xx_YY form
161					$accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2));
162					$accept_lang = basename($accept_lang);
163
164					if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx"))
165					{
166						$user_lang_name = $config['default_lang'] = $accept_lang;
167						break;
168					}
169					else
170					{
171						// No match on xx_YY so try xx
172						$accept_lang = substr($accept_lang, 0, 2);
173						$accept_lang = basename($accept_lang);
174
175						if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx"))
176						{
177							$user_lang_name = $config['default_lang'] = $accept_lang;
178							break;
179						}
180					}
181				}
182			}
183			*/
184		}
185
186		$user_data = $this->data;
187		$lang_set_ext = array();
188
189		/**
190		* Event to load language files and modify user data on every page
191		*
192		* Note: To load language file with this event, see description
193		* of lang_set_ext variable.
194		*
195		* @event core.user_setup
196		* @var	array	user_data			Array with user's data row
197		* @var	string	user_lang_name		Basename of the user's langauge
198		* @var	string	user_date_format	User's date/time format
199		* @var	string	user_timezone		User's timezone, should be one of
200		*							http://www.php.net/manual/en/timezones.php
201		* @var	mixed	lang_set			String or array of language files
202		* @var	array	lang_set_ext		Array containing entries of format
203		* 					array(
204		* 						'ext_name' => (string) [extension name],
205		* 						'lang_set' => (string|array) [language files],
206		* 					)
207		* 					For performance reasons, only load translations
208		* 					that are absolutely needed globally using this
209		* 					event. Use local events otherwise.
210		* @var	mixed	style_id			Style we are going to display
211		* @since 3.1.0-a1
212		*/
213		$vars = array(
214			'user_data',
215			'user_lang_name',
216			'user_date_format',
217			'user_timezone',
218			'lang_set',
219			'lang_set_ext',
220			'style_id',
221		);
222		extract($phpbb_dispatcher->trigger_event('core.user_setup', compact($vars)));
223
224		$this->data = $user_data;
225		$this->lang_name = $user_lang_name;
226		$this->date_format = $user_date_format;
227
228		$this->language->set_user_language($user_lang_name);
229
230		$this->create_timezone($user_timezone);
231
232		$this->add_lang($lang_set);
233		unset($lang_set);
234
235		foreach ($lang_set_ext as $ext_lang_pair)
236		{
237			$this->add_lang_ext($ext_lang_pair['ext_name'], $ext_lang_pair['lang_set']);
238		}
239		unset($lang_set_ext);
240
241		$style_request = $request->variable('style', 0);
242		if ($style_request && (!$config['override_user_style'] || $auth->acl_get('a_styles')) && !defined('ADMIN_START'))
243		{
244			global $SID, $_EXTRA_URL;
245
246			$style_id = $style_request;
247			$SID .= '&amp;style=' . $style_id;
248			$_EXTRA_URL = array('style=' . $style_id);
249		}
250		else
251		{
252			// Set up style
253			$style_id = ($style_id) ? $style_id : ((!$config['override_user_style']) ? $this->data['user_style'] : $config['default_style']);
254		}
255
256		$sql = 'SELECT *
257			FROM ' . STYLES_TABLE . '
258			WHERE style_id = ' . (int) $style_id;
259		$result = $db->sql_query($sql, 3600);
260		$this->style = $db->sql_fetchrow($result);
261		$db->sql_freeresult($result);
262
263		// Fallback to user's standard style
264		if (!$this->style && $style_id != $this->data['user_style'])
265		{
266			$style_id = $this->data['user_style'];
267
268			$sql = 'SELECT *
269				FROM ' . STYLES_TABLE . '
270				WHERE style_id = ' . (int) $style_id;
271			$result = $db->sql_query($sql, 3600);
272			$this->style = $db->sql_fetchrow($result);
273			$db->sql_freeresult($result);
274		}
275
276		// Fallback to board's default style
277		if (!$this->style)
278		{
279			// Verify default style exists in the database
280			$sql = 'SELECT style_id
281				FROM ' . STYLES_TABLE . '
282				WHERE style_id = ' . (int) $config['default_style'];
283			$result = $db->sql_query($sql);
284			$style_id = (int) $db->sql_fetchfield('style_id');
285			$db->sql_freeresult($result);
286
287			if ($style_id > 0)
288			{
289				$db->sql_transaction('begin');
290
291				// Update $user row
292				$sql = 'SELECT *
293					FROM ' . STYLES_TABLE . '
294					WHERE style_id = ' . (int) $config['default_style'];
295				$result = $db->sql_query($sql);
296				$this->style = $db->sql_fetchrow($result);
297				$db->sql_freeresult($result);
298
299				// Update user style preference
300				$sql = 'UPDATE ' . USERS_TABLE . '
301					SET user_style = ' . (int) $style_id . '
302					WHERE user_id = ' . (int) $this->data['user_id'];
303				$db->sql_query($sql);
304
305				$db->sql_transaction('commit');
306			}
307		}
308
309		// This should never happen
310		if (!$this->style)
311		{
312			trigger_error($this->language->lang('NO_STYLE_DATA', $this->data['user_style'], $this->data['user_id']), E_USER_ERROR);
313		}
314
315		// Now parse the cfg file and cache it
316		$parsed_items = $cache->obtain_cfg_items($this->style);
317
318		$check_for = array(
319			'pagination_sep'    => (string) ', '
320		);
321
322		foreach ($check_for as $key => $default_value)
323		{
324			$this->style[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value;
325			settype($this->style[$key], gettype($default_value));
326
327			if (is_string($default_value))
328			{
329				$this->style[$key] = htmlspecialchars($this->style[$key], ENT_COMPAT);
330			}
331		}
332
333		$template->set_style();
334
335		$this->img_lang = $this->lang_name;
336
337		// Call phpbb_user_session_handler() in case external application want to "bend" some variables or replace classes...
338		// After calling it we continue script execution...
339		phpbb_user_session_handler();
340
341		/**
342		* Execute code at the end of user setup
343		*
344		* @event core.user_setup_after
345		* @since 3.1.6-RC1
346		*/
347		$phpbb_dispatcher->dispatch('core.user_setup_after');
348
349		// If this function got called from the error handler we are finished here.
350		if (defined('IN_ERROR_HANDLER'))
351		{
352			return;
353		}
354
355		// Disable board if the install/ directory is still present
356		// For the brave development army we do not care about this, else we need to comment out this every time we develop locally
357		if (!$phpbb_container->getParameter('allow_install_dir') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install'))
358		{
359			// Adjust the message slightly according to the permissions
360			if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))
361			{
362				$message = 'REMOVE_INSTALL';
363			}
364			else
365			{
366				$message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
367			}
368			trigger_error($message);
369		}
370
371		// Is board disabled and user not an admin or moderator?
372		if ($config['board_disable'] && !defined('IN_INSTALL') && !defined('IN_LOGIN') && !defined('SKIP_CHECK_DISABLED') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
373		{
374			if ($this->data['is_bot'])
375			{
376				send_status_line(503, 'Service Unavailable');
377			}
378
379			$message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
380			trigger_error($message);
381		}
382
383		// Is load exceeded?
384		if ($config['limit_load'] && $this->load !== false)
385		{
386			if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN') && !defined('IN_ADMIN'))
387			{
388				// Set board disabled to true to let the admins/mods get the proper notification
389				$config['board_disable'] = '1';
390
391				if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
392				{
393					if ($this->data['is_bot'])
394					{
395						send_status_line(503, 'Service Unavailable');
396					}
397					trigger_error('BOARD_UNAVAILABLE');
398				}
399			}
400		}
401
402		if (isset($this->data['session_viewonline']))
403		{
404			// Make sure the user is able to hide his session
405			if (!$this->data['session_viewonline'])
406			{
407				// Reset online status if not allowed to hide the session...
408				if (!$auth->acl_get('u_hideonline'))
409				{
410					$sql = 'UPDATE ' . SESSIONS_TABLE . '
411						SET session_viewonline = 1
412						WHERE session_user_id = ' . $this->data['user_id'];
413					$db->sql_query($sql);
414					$this->data['session_viewonline'] = 1;
415				}
416			}
417			else if (!$this->data['user_allow_viewonline'])
418			{
419				// the user wants to hide and is allowed to  -> cloaking device on.
420				if ($auth->acl_get('u_hideonline'))
421				{
422					$sql = 'UPDATE ' . SESSIONS_TABLE . '
423						SET session_viewonline = 0
424						WHERE session_user_id = ' . $this->data['user_id'];
425					$db->sql_query($sql);
426					$this->data['session_viewonline'] = 0;
427				}
428			}
429		}
430
431		// Does the user need to change their password? If so, redirect to the
432		// ucp profile reg_details page ... of course do not redirect if we're already in the ucp
433		if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && !empty($this->data['is_registered']) && $auth->acl_get('u_chgpasswd') && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400))
434		{
435			if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx")
436			{
437				redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&amp;mode=reg_details'));
438			}
439		}
440
441		$this->is_setup_flag = true;
442
443		return;
444	}
445
446	/**
447	* More advanced language substitution
448	* Function to mimic sprintf() with the possibility of using phpBB's language system to substitute nullar/singular/plural forms.
449	* Params are the language key and the parameters to be substituted.
450	* This function/functionality is inspired by SHS` and Ashe.
451	*
452	* Example call: <samp>$user->lang('NUM_POSTS_IN_QUEUE', 1);</samp>
453	*
454	* If the first parameter is an array, the elements are used as keys and subkeys to get the language entry:
455	* Example: <samp>$user->lang(array('datetime', 'AGO'), 1)</samp> uses $user->lang['datetime']['AGO'] as language entry.
456	*
457	* @deprecated 3.2.0-dev (To be removed 4.0.0)
458	*/
459	function lang()
460	{
461		$args = func_get_args();
462		return call_user_func_array(array($this->language, 'lang'), $args);
463	}
464
465	/**
466	* Determine which plural form we should use.
467	* For some languages this is not as simple as for English.
468	*
469	* @param $number        int|float   The number we want to get the plural case for. Float numbers are floored.
470	* @param $force_rule    mixed   False to use the plural rule of the language package
471	*                               or an integer to force a certain plural rule
472	* @return int|bool     The plural-case we need to use for the number plural-rule combination, false if $force_rule
473	* 					   was invalid.
474	*
475	* @deprecated: 3.2.0-dev (To be removed: 4.0.0)
476	*/
477	function get_plural_form($number, $force_rule = false)
478	{
479		return $this->language->get_plural_form($number, $force_rule);
480	}
481
482	/**
483	* Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion)
484	*
485	* @param mixed $lang_set specifies the language entries to include
486	* @param bool $use_db internal variable for recursion, do not use	@deprecated 3.2.0-dev (To be removed: 4.0.0)
487	* @param bool $use_help internal variable for recursion, do not use	@deprecated 3.2.0-dev (To be removed: 4.0.0)
488	* @param string $ext_name The extension to load language from, or empty for core files
489	*
490	* Examples:
491	* <code>
492	* $lang_set = array('posting', 'help' => 'faq');
493	* $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq'))
494	* $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq'))
495	* $lang_set = 'posting'
496	* $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting'))
497	* </code>
498	*
499	* Note: $use_db and $use_help should be removed. The old function was kept for BC purposes,
500	* 		so the BC logic is handled here.
501	*
502	* @deprecated: 3.2.0-dev (To be removed: 4.0.0)
503	*/
504	function add_lang($lang_set, $use_db = false, $use_help = false, $ext_name = '')
505	{
506		if (is_array($lang_set))
507		{
508			foreach ($lang_set as $key => $lang_file)
509			{
510				// Please do not delete this line.
511				// We have to force the type here, else [array] language inclusion will not work
512				$key = (string) $key;
513
514				if ($key == 'db')
515				{
516					// This is never used
517					$this->add_lang($lang_file, true, $use_help, $ext_name);
518				}
519				else if ($key == 'help')
520				{
521					$this->add_lang($lang_file, $use_db, true, $ext_name);
522				}
523				else if (!is_array($lang_file))
524				{
525					$this->set_lang($lang_file, $use_help, $ext_name);
526				}
527				else
528				{
529					$this->add_lang($lang_file, $use_db, $use_help, $ext_name);
530				}
531			}
532			unset($lang_set);
533		}
534		else if ($lang_set)
535		{
536			$this->set_lang($lang_set, $use_help, $ext_name);
537		}
538	}
539
540	/**
541	 * BC function for loading language files
542	 *
543	 * @deprecated 3.2.0-dev (To be removed: 4.0.0)
544	 */
545	private function set_lang($lang_set, $use_help, $ext_name)
546	{
547		if (empty($ext_name))
548		{
549			$ext_name = null;
550		}
551
552		if ($use_help && strpos($lang_set, '/') !== false)
553		{
554			$component = dirname($lang_set) . '/help_' . basename($lang_set);
555
556			if ($component[0] === '/')
557			{
558				$component = substr($component, 1);
559			}
560		}
561		else
562		{
563			$component = (($use_help) ? 'help_' : '') . $lang_set;
564		}
565
566		$this->language->add_lang($component, $ext_name);
567	}
568
569	/**
570	* Add Language Items from an extension - use_db and use_help are assigned where needed (only use them to force inclusion)
571	*
572	* @param string $ext_name The extension to load language from, or empty for core files
573	* @param mixed $lang_set specifies the language entries to include
574	* @param bool $use_db internal variable for recursion, do not use
575	* @param bool $use_help internal variable for recursion, do not use
576	*
577	* Note: $use_db and $use_help should be removed. Kept for BC purposes.
578	*
579	* @deprecated: 3.2.0-dev (To be removed: 4.0.0)
580	*/
581	function add_lang_ext($ext_name, $lang_set, $use_db = false, $use_help = false)
582	{
583		if ($ext_name === '/')
584		{
585			$ext_name = '';
586		}
587
588		$this->add_lang($lang_set, $use_db, $use_help, $ext_name);
589	}
590
591	/**
592	* Format user date
593	*
594	* @param int $gmepoch unix timestamp
595	* @param string $format date format in date() notation. | used to indicate relative dates, for example |d m Y|, h:i is translated to Today, h:i.
596	* @param bool $forcedate force non-relative date format.
597	*
598	* @return mixed translated date
599	*/
600	function format_date($gmepoch, $format = false, $forcedate = false)
601	{
602		global $phpbb_dispatcher;
603		static $utc;
604
605		if (!isset($utc))
606		{
607			$utc = new \DateTimeZone('UTC');
608		}
609
610		$format_date_override = false;
611		$function_arguments = func_get_args();
612		/**
613		* Execute code and/or override format_date()
614		*
615		* To override the format_date() function generated value
616		* set $format_date_override to new return value
617		*
618		* @event core.user_format_date_override
619		* @var DateTimeZone	utc Is DateTimeZone in UTC
620		* @var array function_arguments is array comprising a function's argument list
621		* @var string format_date_override Shall we return custom format (string) or not (false)
622		* @since 3.2.1-RC1
623		*/
624		$vars = array('utc', 'function_arguments', 'format_date_override');
625		extract($phpbb_dispatcher->trigger_event('core.user_format_date_override', compact($vars)));
626
627		if (!$format_date_override)
628		{
629			$time = new $this->datetime($this, '@' . (int) $gmepoch, $utc);
630			$time->setTimezone($this->create_timezone());
631
632			return $time->format($format, $forcedate);
633		}
634		else
635		{
636			return $format_date_override;
637		}
638	}
639
640	/**
641	 * Create a DateTimeZone object in the context of the current user
642	 *
643	 * @param string $user_timezone Time zone of the current user.
644	 * @return \DateTimeZone DateTimeZone object linked to the current users locale
645	 */
646	public function create_timezone($user_timezone = null)
647	{
648		if (!$this->timezone)
649		{
650			if (!$user_timezone)
651			{
652				global $config;
653				$user_timezone = ($this->data['user_id'] != ANONYMOUS) ? $this->data['user_timezone'] : $config['board_timezone'];
654			}
655
656			try
657			{
658				$this->timezone = new \DateTimeZone($user_timezone);
659			}
660			catch (\Exception $e)
661			{
662				// If the timezone the user has selected is invalid, we fall back to UTC.
663				$this->timezone = new \DateTimeZone('UTC');
664			}
665		}
666
667		return $this->timezone;
668	}
669
670	/**
671	* Create a \phpbb\datetime object in the context of the current user
672	*
673	* @since 3.1
674	* @param string $time String in a format accepted by strtotime().
675	* @param DateTimeZone $timezone Time zone of the time.
676	* @return \phpbb\datetime Date time object linked to the current users locale
677	*/
678	public function create_datetime($time = 'now', \DateTimeZone $timezone = null)
679	{
680		$timezone = $timezone ?: $this->create_timezone();
681		return new $this->datetime($this, $time, $timezone);
682	}
683
684	/**
685	* Get the UNIX timestamp for a datetime in the users timezone, so we can store it in the database.
686	*
687	* @param	string			$format		Format of the entered date/time
688	* @param	string			$time		Date/time with the timezone applied
689	* @param	DateTimeZone	$timezone	Timezone of the date/time, falls back to timezone of current user
690	* @return	int			Returns the unix timestamp
691	*/
692	public function get_timestamp_from_format($format, $time, \DateTimeZone $timezone = null)
693	{
694		$timezone = $timezone ?: $this->create_timezone();
695		$date = \DateTime::createFromFormat($format, $time, $timezone);
696		return ($date !== false) ? $date->format('U') : false;
697	}
698
699	/**
700	* Get language id currently used by the user
701	*/
702	function get_iso_lang_id()
703	{
704		global $config, $db;
705
706		if (!empty($this->lang_id))
707		{
708			return $this->lang_id;
709		}
710
711		if (!$this->lang_name)
712		{
713			$this->lang_name = $config['default_lang'];
714		}
715
716		$sql = 'SELECT lang_id
717			FROM ' . LANG_TABLE . "
718			WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'";
719		$result = $db->sql_query($sql);
720		$this->lang_id = (int) $db->sql_fetchfield('lang_id');
721		$db->sql_freeresult($result);
722
723		return $this->lang_id;
724	}
725
726	/**
727	* Get users profile fields
728	*/
729	function get_profile_fields($user_id)
730	{
731		global $db;
732
733		if (isset($this->profile_fields))
734		{
735			return;
736		}
737
738		$sql = 'SELECT *
739			FROM ' . PROFILE_FIELDS_DATA_TABLE . "
740			WHERE user_id = $user_id";
741		$result = $db->sql_query_limit($sql, 1);
742		$this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row;
743		$db->sql_freeresult($result);
744	}
745
746	/**
747	* Specify/Get image
748	*/
749	function img($img, $alt = '')
750	{
751		$title = '';
752
753		if ($alt)
754		{
755			$alt = $this->language->lang($alt);
756			$title = ' title="' . $alt . '"';
757		}
758		return '<span class="imageset ' . $img . '"' . $title . '>' . $alt . '</span>';
759	}
760
761	/**
762	* Get option bit field from user options.
763	*
764	* @param int $key option key, as defined in $keyoptions property.
765	* @param int $data bit field value to use, or false to use $this->data['user_options']
766	* @return bool true if the option is set in the bit field, false otherwise
767	*/
768	function optionget($key, $data = false)
769	{
770		$var = ($data !== false) ? $data : $this->data['user_options'];
771		return phpbb_optionget($this->keyoptions[$key], $var);
772	}
773
774	/**
775	* Set option bit field for user options.
776	*
777	* @param int $key Option key, as defined in $keyoptions property.
778	* @param bool $value True to set the option, false to clear the option.
779	* @param int $data Current bit field value, or false to use $this->data['user_options']
780	* @return int|bool If $data is false, the bit field is modified and
781	*                  written back to $this->data['user_options'], and
782	*                  return value is true if the bit field changed and
783	*                  false otherwise. If $data is not false, the new
784	*                  bitfield value is returned.
785	*/
786	function optionset($key, $value, $data = false)
787	{
788		$var = ($data !== false) ? $data : $this->data['user_options'];
789
790		$new_var = phpbb_optionset($this->keyoptions[$key], $value, $var);
791
792		if ($data === false)
793		{
794			if ($new_var != $var)
795			{
796				$this->data['user_options'] = $new_var;
797				return true;
798			}
799			else
800			{
801				return false;
802			}
803		}
804		else
805		{
806			return $new_var;
807		}
808	}
809
810	/**
811	* Function to make the user leave the NEWLY_REGISTERED system group.
812	* @access public
813	*/
814	function leave_newly_registered()
815	{
816		if (empty($this->data['user_new']))
817		{
818			return false;
819		}
820
821		if (!function_exists('remove_newly_registered'))
822		{
823			global $phpbb_root_path, $phpEx;
824
825			include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
826		}
827		if ($group = remove_newly_registered($this->data['user_id'], $this->data))
828		{
829			$this->data['group_id'] = $group;
830
831		}
832		$this->data['user_permissions'] = '';
833		$this->data['user_new'] = 0;
834
835		return true;
836	}
837
838	/**
839	* Returns all password protected forum ids the user is currently NOT authenticated for.
840	*
841	* @return array     Array of forum ids
842	* @access public
843	*/
844	function get_passworded_forums()
845	{
846		global $db;
847
848		$sql = 'SELECT f.forum_id, fa.user_id
849			FROM ' . FORUMS_TABLE . ' f
850			LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa
851				ON (fa.forum_id = f.forum_id
852					AND fa.session_id = '" . $db->sql_escape($this->session_id) . "')
853			WHERE f.forum_password <> ''";
854		$result = $db->sql_query($sql);
855
856		$forum_ids = array();
857		while ($row = $db->sql_fetchrow($result))
858		{
859			$forum_id = (int) $row['forum_id'];
860
861			if ($row['user_id'] != $this->data['user_id'])
862			{
863				$forum_ids[$forum_id] = $forum_id;
864			}
865		}
866		$db->sql_freeresult($result);
867
868		return $forum_ids;
869	}
870}
871