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
14/**
15* @ignore
16*/
17if (!defined('IN_PHPBB'))
18{
19	exit;
20}
21
22class acp_forums
23{
24	var $u_action;
25	var $parent_id = 0;
26
27	function main($id, $mode)
28	{
29		global $db, $user, $auth, $template, $cache, $request, $phpbb_dispatcher;
30		global $phpbb_admin_path, $phpbb_root_path, $phpEx, $phpbb_log;
31
32		$user->add_lang('acp/forums');
33		$this->tpl_name = 'acp_forums';
34		$this->page_title = 'ACP_MANAGE_FORUMS';
35
36		$form_key = 'acp_forums';
37		add_form_key($form_key);
38
39		$action		= $request->variable('action', '');
40		$update		= (isset($_POST['update'])) ? true : false;
41		$forum_id	= $request->variable('f', 0);
42
43		$this->parent_id	= $request->variable('parent_id', 0);
44		$forum_data = $errors = array();
45		if ($update && !check_form_key($form_key))
46		{
47			$update = false;
48			$errors[] = $user->lang['FORM_INVALID'];
49		}
50
51		// Check additional permissions
52		switch ($action)
53		{
54			case 'progress_bar':
55				$start = $request->variable('start', 0);
56				$total = $request->variable('total', 0);
57
58				$this->display_progress_bar($start, $total);
59			break;
60
61			case 'delete':
62
63				if (!$auth->acl_get('a_forumdel'))
64				{
65					trigger_error($user->lang['NO_PERMISSION_FORUM_DELETE'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
66				}
67
68			break;
69
70			case 'add':
71
72				if (!$auth->acl_get('a_forumadd'))
73				{
74					trigger_error($user->lang['NO_PERMISSION_FORUM_ADD'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
75				}
76
77			break;
78		}
79
80		// Major routines
81		if ($update)
82		{
83			switch ($action)
84			{
85				case 'delete':
86					$action_subforums	= $request->variable('action_subforums', '');
87					$subforums_to_id	= $request->variable('subforums_to_id', 0);
88					$action_posts		= $request->variable('action_posts', '');
89					$posts_to_id		= $request->variable('posts_to_id', 0);
90
91					$errors = $this->delete_forum($forum_id, $action_posts, $action_subforums, $posts_to_id, $subforums_to_id);
92
93					if (count($errors))
94					{
95						break;
96					}
97
98					$auth->acl_clear_prefetch();
99					$cache->destroy('sql', FORUMS_TABLE);
100
101					trigger_error($user->lang['FORUM_DELETED'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
102
103				break;
104
105				case 'edit':
106					$forum_data = array(
107						'forum_id'		=>	$forum_id
108					);
109
110				// No break here
111
112				case 'add':
113
114					$forum_data += array(
115						'parent_id'				=> $request->variable('forum_parent_id', $this->parent_id),
116						'forum_type'			=> $request->variable('forum_type', FORUM_POST),
117						'type_action'			=> $request->variable('type_action', ''),
118						'forum_status'			=> $request->variable('forum_status', ITEM_UNLOCKED),
119						'forum_parents'			=> '',
120						'forum_name'			=> $request->variable('forum_name', '', true),
121						'forum_link'			=> $request->variable('forum_link', ''),
122						'forum_link_track'		=> $request->variable('forum_link_track', false),
123						'forum_desc'			=> $request->variable('forum_desc', '', true),
124						'forum_desc_uid'		=> '',
125						'forum_desc_options'	=> 7,
126						'forum_desc_bitfield'	=> '',
127						'forum_rules'			=> $request->variable('forum_rules', '', true),
128						'forum_rules_uid'		=> '',
129						'forum_rules_options'	=> 7,
130						'forum_rules_bitfield'	=> '',
131						'forum_rules_link'		=> $request->variable('forum_rules_link', ''),
132						'forum_image'			=> $request->variable('forum_image', ''),
133						'forum_style'			=> $request->variable('forum_style', 0),
134						'display_subforum_list'	=> $request->variable('display_subforum_list', true),
135						'display_subforum_limit'=> $request->variable('display_subforum_limit', false),
136						'display_on_index'		=> $request->variable('display_on_index', true),
137						'forum_topics_per_page'	=> $request->variable('topics_per_page', 0),
138						'enable_indexing'		=> $request->variable('enable_indexing', true),
139						'enable_icons'			=> $request->variable('enable_icons', true),
140						'enable_prune'			=> $request->variable('enable_prune', false),
141						'enable_post_review'	=> $request->variable('enable_post_review', true),
142						'enable_quick_reply'	=> $request->variable('enable_quick_reply', false),
143						'enable_shadow_prune'	=> $request->variable('enable_shadow_prune', false),
144						'prune_days'			=> $request->variable('prune_days', 7),
145						'prune_viewed'			=> $request->variable('prune_viewed', 7),
146						'prune_freq'			=> $request->variable('prune_freq', 1),
147						'prune_old_polls'		=> $request->variable('prune_old_polls', false),
148						'prune_announce'		=> $request->variable('prune_announce', false),
149						'prune_sticky'			=> $request->variable('prune_sticky', false),
150						'prune_shadow_days'		=> $request->variable('prune_shadow_days', 7),
151						'prune_shadow_freq'		=> $request->variable('prune_shadow_freq', 1),
152						'forum_password'		=> $request->variable('forum_password', '', true),
153						'forum_password_confirm'=> $request->variable('forum_password_confirm', '', true),
154						'forum_password_unset'	=> $request->variable('forum_password_unset', false),
155					);
156
157					/**
158					* Request forum data and operate on it (parse texts, etc.)
159					*
160					* @event core.acp_manage_forums_request_data
161					* @var	string	action		Type of the action: add|edit
162					* @var	array	forum_data	Array with new forum data
163					* @since 3.1.0-a1
164					*/
165					$vars = array('action', 'forum_data');
166					extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_request_data', compact($vars)));
167
168					// On add, add empty forum_options... else do not consider it (not updating it)
169					if ($action == 'add')
170					{
171						$forum_data['forum_options'] = 0;
172					}
173
174					// Use link_display_on_index setting if forum type is link
175					if ($forum_data['forum_type'] == FORUM_LINK)
176					{
177						$forum_data['display_on_index'] = $request->variable('link_display_on_index', false);
178					}
179
180					// Linked forums and categories are not able to be locked...
181					if ($forum_data['forum_type'] == FORUM_LINK || $forum_data['forum_type'] == FORUM_CAT)
182					{
183						$forum_data['forum_status'] = ITEM_UNLOCKED;
184					}
185
186					$forum_data['show_active'] = ($forum_data['forum_type'] == FORUM_POST) ? $request->variable('display_recent', true) : $request->variable('display_active', false);
187
188					// Get data for forum rules if specified...
189					if ($forum_data['forum_rules'])
190					{
191						generate_text_for_storage($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options'], $request->variable('rules_parse_bbcode', false), $request->variable('rules_parse_urls', false), $request->variable('rules_parse_smilies', false));
192					}
193
194					// Get data for forum description if specified
195					if ($forum_data['forum_desc'])
196					{
197						generate_text_for_storage($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_bitfield'], $forum_data['forum_desc_options'], $request->variable('desc_parse_bbcode', false), $request->variable('desc_parse_urls', false), $request->variable('desc_parse_smilies', false));
198					}
199
200					$errors = $this->update_forum_data($forum_data);
201
202					if (!count($errors))
203					{
204						$forum_perm_from = $request->variable('forum_perm_from', 0);
205						$cache->destroy('sql', FORUMS_TABLE);
206
207						$copied_permissions = false;
208						// Copy permissions?
209						if ($forum_perm_from && $forum_perm_from != $forum_data['forum_id'] &&
210							($action != 'edit' || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth'))))
211						{
212							copy_forum_permissions($forum_perm_from, $forum_data['forum_id'], ($action == 'edit') ? true : false);
213							phpbb_cache_moderators($db, $cache, $auth);
214							$copied_permissions = true;
215						}
216/* Commented out because of questionable UI workflow - re-visit for 3.0.7
217						else if (!$this->parent_id && $action != 'edit' && $auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth'))
218						{
219							$this->copy_permission_page($forum_data);
220							return;
221						}
222*/
223						$auth->acl_clear_prefetch();
224
225						$acl_url = '&amp;mode=setting_forum_local&amp;forum_id[]=' . $forum_data['forum_id'];
226
227						$message = ($action == 'add') ? $user->lang['FORUM_CREATED'] : $user->lang['FORUM_UPDATED'];
228
229						// redirect directly to permission settings screen if authed
230						if ($action == 'add' && !$copied_permissions && $auth->acl_get('a_fauth'))
231						{
232							$message .= '<br /><br />' . sprintf($user->lang['REDIRECT_ACL'], '<a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url) . '">', '</a>');
233
234							meta_refresh(4, append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url));
235						}
236
237						trigger_error($message . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
238					}
239
240				break;
241			}
242		}
243
244		switch ($action)
245		{
246			case 'move_up':
247			case 'move_down':
248
249				if (!$forum_id)
250				{
251					trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
252				}
253
254				$sql = 'SELECT *
255					FROM ' . FORUMS_TABLE . "
256					WHERE forum_id = $forum_id";
257				$result = $db->sql_query($sql);
258				$row = $db->sql_fetchrow($result);
259				$db->sql_freeresult($result);
260
261				if (!$row)
262				{
263					trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
264				}
265
266				$move_forum_name = $this->move_forum_by($row, $action, 1);
267
268				if ($move_forum_name !== false)
269				{
270					$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_' . strtoupper($action), false, array($row['forum_name'], $move_forum_name));
271					$cache->destroy('sql', FORUMS_TABLE);
272				}
273
274				if ($request->is_ajax())
275				{
276					$json_response = new \phpbb\json_response;
277					$json_response->send(array('success' => ($move_forum_name !== false)));
278				}
279
280			break;
281
282			case 'sync':
283				if (!$forum_id)
284				{
285					trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
286				}
287
288				@set_time_limit(0);
289
290				$sql = 'SELECT forum_name, (forum_topics_approved + forum_topics_unapproved + forum_topics_softdeleted) AS total_topics
291					FROM ' . FORUMS_TABLE . "
292					WHERE forum_id = $forum_id";
293				$result = $db->sql_query($sql);
294				$row = $db->sql_fetchrow($result);
295				$db->sql_freeresult($result);
296
297				if (!$row)
298				{
299					trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
300				}
301
302				if ($row['total_topics'])
303				{
304					$sql = 'SELECT MIN(topic_id) as min_topic_id, MAX(topic_id) as max_topic_id
305						FROM ' . TOPICS_TABLE . '
306						WHERE forum_id = ' . $forum_id;
307					$result = $db->sql_query($sql);
308					$row2 = $db->sql_fetchrow($result);
309					$db->sql_freeresult($result);
310
311					// Typecast to int if there is no data available
312					$row2['min_topic_id'] = (int) $row2['min_topic_id'];
313					$row2['max_topic_id'] = (int) $row2['max_topic_id'];
314
315					$start = $request->variable('start', $row2['min_topic_id']);
316
317					$batch_size = 2000;
318					$end = $start + $batch_size;
319
320					// Sync all topics in batch mode...
321					sync('topic', 'range', 'topic_id BETWEEN ' . $start . ' AND ' . $end, true, true);
322
323					if ($end < $row2['max_topic_id'])
324					{
325						// We really need to find a way of showing statistics... no progress here
326						$sql = 'SELECT COUNT(topic_id) as num_topics
327							FROM ' . TOPICS_TABLE . '
328							WHERE forum_id = ' . $forum_id . '
329								AND topic_id BETWEEN ' . $start . ' AND ' . $end;
330						$result = $db->sql_query($sql);
331						$topics_done = $request->variable('topics_done', 0) + (int) $db->sql_fetchfield('num_topics');
332						$db->sql_freeresult($result);
333
334						$start += $batch_size;
335
336						$url = $this->u_action . "&amp;parent_id={$this->parent_id}&amp;f=$forum_id&amp;action=sync&amp;start=$start&amp;topics_done=$topics_done&amp;total={$row['total_topics']}";
337
338						meta_refresh(0, $url);
339
340						$template->assign_vars(array(
341							'U_PROGRESS_BAR'		=> $this->u_action . "&amp;action=progress_bar&amp;start=$topics_done&amp;total={$row['total_topics']}",
342							'UA_PROGRESS_BAR'		=> addslashes($this->u_action . "&amp;action=progress_bar&amp;start=$topics_done&amp;total={$row['total_topics']}"),
343							'S_CONTINUE_SYNC'		=> true,
344							'L_PROGRESS_EXPLAIN'	=> sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $topics_done, $row['total_topics']))
345						);
346
347						return;
348					}
349				}
350
351				$url = $this->u_action . "&amp;parent_id={$this->parent_id}&amp;f=$forum_id&amp;action=sync_forum";
352				meta_refresh(0, $url);
353
354				$template->assign_vars(array(
355					'U_PROGRESS_BAR'		=> $this->u_action . '&amp;action=progress_bar',
356					'UA_PROGRESS_BAR'		=> addslashes($this->u_action . '&amp;action=progress_bar'),
357					'S_CONTINUE_SYNC'		=> true,
358					'L_PROGRESS_EXPLAIN'	=> sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], 0, $row['total_topics']))
359				);
360
361				return;
362
363			break;
364
365			case 'sync_forum':
366
367				$sql = 'SELECT forum_name, forum_type
368					FROM ' . FORUMS_TABLE . "
369					WHERE forum_id = $forum_id";
370				$result = $db->sql_query($sql);
371				$row = $db->sql_fetchrow($result);
372				$db->sql_freeresult($result);
373
374				if (!$row)
375				{
376					trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
377				}
378
379				sync('forum', 'forum_id', $forum_id, false, true);
380
381				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_SYNC', false, array($row['forum_name']));
382
383				$cache->destroy('sql', FORUMS_TABLE);
384
385				$template->assign_var('L_FORUM_RESYNCED', sprintf($user->lang['FORUM_RESYNCED'], $row['forum_name']));
386
387			break;
388
389			case 'add':
390			case 'edit':
391
392				if ($update)
393				{
394					$forum_data['forum_flags'] = 0;
395					$forum_data['forum_flags'] += ($request->variable('forum_link_track', false)) ? FORUM_FLAG_LINK_TRACK : 0;
396					$forum_data['forum_flags'] += ($request->variable('prune_old_polls', false)) ? FORUM_FLAG_PRUNE_POLL : 0;
397					$forum_data['forum_flags'] += ($request->variable('prune_announce', false)) ? FORUM_FLAG_PRUNE_ANNOUNCE : 0;
398					$forum_data['forum_flags'] += ($request->variable('prune_sticky', false)) ? FORUM_FLAG_PRUNE_STICKY : 0;
399					$forum_data['forum_flags'] += ($forum_data['show_active']) ? FORUM_FLAG_ACTIVE_TOPICS : 0;
400					$forum_data['forum_flags'] += ($request->variable('enable_post_review', true)) ? FORUM_FLAG_POST_REVIEW : 0;
401					$forum_data['forum_flags'] += ($request->variable('enable_quick_reply', false)) ? FORUM_FLAG_QUICK_REPLY : 0;
402				}
403
404				// Initialise $row, so we always have it in the event
405				$row = array();
406
407				// Show form to create/modify a forum
408				if ($action == 'edit')
409				{
410					$this->page_title = 'EDIT_FORUM';
411					$row = $this->get_forum_info($forum_id);
412					$old_forum_type = $row['forum_type'];
413
414					if (!$update)
415					{
416						$forum_data = $row;
417					}
418					else
419					{
420						$forum_data['left_id'] = $row['left_id'];
421						$forum_data['right_id'] = $row['right_id'];
422					}
423
424					// Make sure no direct child forums are able to be selected as parents.
425					$exclude_forums = array();
426					foreach (get_forum_branch($forum_id, 'children') as $row)
427					{
428						$exclude_forums[] = $row['forum_id'];
429					}
430
431					$parents_list = make_forum_select($forum_data['parent_id'], $exclude_forums, false, false, false);
432
433					$forum_data['forum_password_confirm'] = $forum_data['forum_password'];
434				}
435				else
436				{
437					$this->page_title = 'CREATE_FORUM';
438
439					$forum_id = $this->parent_id;
440					$parents_list = make_forum_select($this->parent_id, false, false, false, false);
441
442					// Fill forum data with default values
443					if (!$update)
444					{
445						$forum_data = array(
446							'parent_id'				=> $this->parent_id,
447							'forum_type'			=> FORUM_POST,
448							'forum_status'			=> ITEM_UNLOCKED,
449							'forum_name'			=> $request->variable('forum_name', '', true),
450							'forum_link'			=> '',
451							'forum_link_track'		=> false,
452							'forum_desc'			=> '',
453							'forum_rules'			=> '',
454							'forum_rules_link'		=> '',
455							'forum_image'			=> '',
456							'forum_style'			=> 0,
457							'display_subforum_list'	=> true,
458							'display_subforum_limit'	=> false,
459							'display_on_index'		=> true,
460							'forum_topics_per_page'	=> 0,
461							'enable_indexing'		=> true,
462							'enable_icons'			=> true,
463							'enable_prune'			=> false,
464							'prune_days'			=> 7,
465							'prune_viewed'			=> 7,
466							'prune_freq'			=> 1,
467							'enable_shadow_prune'		=> false,
468							'prune_shadow_days'		=> 7,
469							'prune_shadow_freq'		=> 1,
470							'forum_flags'			=> FORUM_FLAG_POST_REVIEW + FORUM_FLAG_ACTIVE_TOPICS,
471							'forum_options'			=> 0,
472							'forum_password'		=> '',
473							'forum_password_confirm'=> '',
474						);
475					}
476				}
477
478				/**
479				* Initialise data before we display the add/edit form
480				*
481				* @event core.acp_manage_forums_initialise_data
482				* @var	string	action		Type of the action: add|edit
483				* @var	bool	update		Do we display the form only
484				*							or did the user press submit
485				* @var	int		forum_id	When editing: the forum id,
486				*							when creating: the parent forum id
487				* @var	array	row			Array with current forum data
488				*							empty when creating new forum
489				* @var	array	forum_data	Array with new forum data
490				* @var	string	parents_list	List of parent options
491				* @since 3.1.0-a1
492				*/
493				$vars = array('action', 'update', 'forum_id', 'row', 'forum_data', 'parents_list');
494				extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_initialise_data', compact($vars)));
495
496				$forum_rules_data = array(
497					'text'			=> $forum_data['forum_rules'],
498					'allow_bbcode'	=> true,
499					'allow_smilies'	=> true,
500					'allow_urls'	=> true
501				);
502
503				$forum_desc_data = array(
504					'text'			=> $forum_data['forum_desc'],
505					'allow_bbcode'	=> true,
506					'allow_smilies'	=> true,
507					'allow_urls'	=> true
508				);
509
510				$forum_rules_preview = '';
511
512				// Parse rules if specified
513				if ($forum_data['forum_rules'])
514				{
515					if (!isset($forum_data['forum_rules_uid']))
516					{
517						// Before we are able to display the preview and plane text, we need to parse our $request->variable()'d value...
518						$forum_data['forum_rules_uid'] = '';
519						$forum_data['forum_rules_bitfield'] = '';
520						$forum_data['forum_rules_options'] = 0;
521
522						generate_text_for_storage($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options'], $request->variable('rules_allow_bbcode', false), $request->variable('rules_allow_urls', false), $request->variable('rules_allow_smilies', false));
523					}
524
525					// Generate preview content
526					$forum_rules_preview = generate_text_for_display($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options']);
527
528					// decode...
529					$forum_rules_data = generate_text_for_edit($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_options']);
530				}
531
532				// Parse desciption if specified
533				if ($forum_data['forum_desc'])
534				{
535					if (!isset($forum_data['forum_desc_uid']))
536					{
537						// Before we are able to display the preview and plane text, we need to parse our $request->variable()'d value...
538						$forum_data['forum_desc_uid'] = '';
539						$forum_data['forum_desc_bitfield'] = '';
540						$forum_data['forum_desc_options'] = 0;
541
542						generate_text_for_storage($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_bitfield'], $forum_data['forum_desc_options'], $request->variable('desc_allow_bbcode', false), $request->variable('desc_allow_urls', false), $request->variable('desc_allow_smilies', false));
543					}
544
545					// decode...
546					$forum_desc_data = generate_text_for_edit($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_options']);
547				}
548
549				$forum_type_options = '';
550				$forum_type_ary = array(FORUM_CAT => 'CAT', FORUM_POST => 'FORUM', FORUM_LINK => 'LINK');
551
552				foreach ($forum_type_ary as $value => $lang)
553				{
554					$forum_type_options .= '<option value="' . $value . '"' . (($value == $forum_data['forum_type']) ? ' selected="selected"' : '') . '>' . $user->lang['TYPE_' . $lang] . '</option>';
555				}
556
557				$styles_list = style_select($forum_data['forum_style'], true);
558
559				$statuslist = '<option value="' . ITEM_UNLOCKED . '"' . (($forum_data['forum_status'] == ITEM_UNLOCKED) ? ' selected="selected"' : '') . '>' . $user->lang['UNLOCKED'] . '</option><option value="' . ITEM_LOCKED . '"' . (($forum_data['forum_status'] == ITEM_LOCKED) ? ' selected="selected"' : '') . '>' . $user->lang['LOCKED'] . '</option>';
560
561				$sql = 'SELECT forum_id
562					FROM ' . FORUMS_TABLE . '
563					WHERE forum_type = ' . FORUM_POST . "
564						AND forum_id <> $forum_id";
565				$result = $db->sql_query_limit($sql, 1);
566
567				$postable_forum_exists = false;
568				if ($db->sql_fetchrow($result))
569				{
570					$postable_forum_exists = true;
571				}
572				$db->sql_freeresult($result);
573
574				// Subforum move options
575				if ($action == 'edit' && $forum_data['forum_type'] == FORUM_CAT)
576				{
577					$subforums_id = array();
578					$subforums = get_forum_branch($forum_id, 'children');
579
580					foreach ($subforums as $row)
581					{
582						$subforums_id[] = $row['forum_id'];
583					}
584
585					$forums_list = make_forum_select($forum_data['parent_id'], $subforums_id);
586
587					if ($postable_forum_exists)
588					{
589						$template->assign_vars(array(
590							'S_MOVE_FORUM_OPTIONS'		=> make_forum_select($forum_data['parent_id'], $subforums_id)) // , false, true, false???
591						);
592					}
593
594					$template->assign_vars(array(
595						'S_HAS_SUBFORUMS'		=> ($forum_data['right_id'] - $forum_data['left_id'] > 1) ? true : false,
596						'S_FORUMS_LIST'			=> $forums_list)
597					);
598				}
599				else if ($postable_forum_exists)
600				{
601					$template->assign_vars(array(
602						'S_MOVE_FORUM_OPTIONS'		=> make_forum_select($forum_data['parent_id'], $forum_id, false, true, false))
603					);
604				}
605
606				$s_show_display_on_index = false;
607
608				if ($forum_data['parent_id'] > 0)
609				{
610					// if this forum is a subforum put the "display on index" checkbox
611					if ($parent_info = $this->get_forum_info($forum_data['parent_id']))
612					{
613						if ($parent_info['parent_id'] > 0 || $parent_info['forum_type'] == FORUM_CAT)
614						{
615							$s_show_display_on_index = true;
616						}
617					}
618				}
619
620				if (strlen($forum_data['forum_password']) == 32)
621				{
622					$errors[] = $user->lang['FORUM_PASSWORD_OLD'];
623				}
624
625				$template_data = array(
626					'S_EDIT_FORUM'		=> true,
627					'S_ERROR'			=> (count($errors)) ? true : false,
628					'S_PARENT_ID'		=> $this->parent_id,
629					'S_FORUM_PARENT_ID'	=> $forum_data['parent_id'],
630					'S_ADD_ACTION'		=> ($action == 'add') ? true : false,
631
632					'U_BACK'		=> $this->u_action . '&amp;parent_id=' . $this->parent_id,
633					'U_EDIT_ACTION'	=> $this->u_action . "&amp;parent_id={$this->parent_id}&amp;action=$action&amp;f=$forum_id",
634
635					'L_COPY_PERMISSIONS_EXPLAIN'	=> $user->lang['COPY_PERMISSIONS_' . strtoupper($action) . '_EXPLAIN'],
636					'L_TITLE'						=> $user->lang[$this->page_title],
637					'ERROR_MSG'						=> (count($errors)) ? implode('<br />', $errors) : '',
638
639					'FORUM_NAME'				=> $forum_data['forum_name'],
640					'FORUM_DATA_LINK'			=> $forum_data['forum_link'],
641					'FORUM_IMAGE'				=> $forum_data['forum_image'],
642					'FORUM_IMAGE_SRC'			=> ($forum_data['forum_image']) ? $phpbb_root_path . $forum_data['forum_image'] : '',
643					'FORUM_POST'				=> FORUM_POST,
644					'FORUM_LINK'				=> FORUM_LINK,
645					'FORUM_CAT'					=> FORUM_CAT,
646					'PRUNE_FREQ'				=> $forum_data['prune_freq'],
647					'PRUNE_DAYS'				=> $forum_data['prune_days'],
648					'PRUNE_VIEWED'				=> $forum_data['prune_viewed'],
649					'PRUNE_SHADOW_FREQ'			=> $forum_data['prune_shadow_freq'],
650					'PRUNE_SHADOW_DAYS'			=> $forum_data['prune_shadow_days'],
651					'TOPICS_PER_PAGE'			=> $forum_data['forum_topics_per_page'],
652					'FORUM_RULES_LINK'			=> $forum_data['forum_rules_link'],
653					'FORUM_RULES'				=> $forum_data['forum_rules'],
654					'FORUM_RULES_PREVIEW'		=> $forum_rules_preview,
655					'FORUM_RULES_PLAIN'			=> $forum_rules_data['text'],
656					'S_BBCODE_CHECKED'			=> ($forum_rules_data['allow_bbcode']) ? true : false,
657					'S_SMILIES_CHECKED'			=> ($forum_rules_data['allow_smilies']) ? true : false,
658					'S_URLS_CHECKED'			=> ($forum_rules_data['allow_urls']) ? true : false,
659					'S_FORUM_PASSWORD_SET'		=> (empty($forum_data['forum_password'])) ? false : true,
660
661					'FORUM_DESC'				=> $forum_desc_data['text'],
662					'S_DESC_BBCODE_CHECKED'		=> ($forum_desc_data['allow_bbcode']) ? true : false,
663					'S_DESC_SMILIES_CHECKED'	=> ($forum_desc_data['allow_smilies']) ? true : false,
664					'S_DESC_URLS_CHECKED'		=> ($forum_desc_data['allow_urls']) ? true : false,
665
666					'S_FORUM_TYPE_OPTIONS'		=> $forum_type_options,
667					'S_STATUS_OPTIONS'			=> $statuslist,
668					'S_PARENT_OPTIONS'			=> $parents_list,
669					'S_STYLES_OPTIONS'			=> $styles_list,
670					'S_FORUM_OPTIONS'			=> make_forum_select(($action == 'add') ? $forum_data['parent_id'] : false, ($action == 'edit') ? $forum_data['forum_id'] : false, false, false, false),
671					'S_SHOW_DISPLAY_ON_INDEX'	=> $s_show_display_on_index,
672					'S_FORUM_POST'				=> ($forum_data['forum_type'] == FORUM_POST) ? true : false,
673					'S_FORUM_ORIG_POST'			=> (isset($old_forum_type) && $old_forum_type == FORUM_POST) ? true : false,
674					'S_FORUM_ORIG_CAT'			=> (isset($old_forum_type) && $old_forum_type == FORUM_CAT) ? true : false,
675					'S_FORUM_ORIG_LINK'			=> (isset($old_forum_type) && $old_forum_type == FORUM_LINK) ? true : false,
676					'S_FORUM_LINK'				=> ($forum_data['forum_type'] == FORUM_LINK) ? true : false,
677					'S_FORUM_CAT'				=> ($forum_data['forum_type'] == FORUM_CAT) ? true : false,
678					'S_ENABLE_INDEXING'			=> ($forum_data['enable_indexing']) ? true : false,
679					'S_TOPIC_ICONS'				=> ($forum_data['enable_icons']) ? true : false,
680					'S_DISPLAY_SUBFORUM_LIST'	=> ($forum_data['display_subforum_list']) ? true : false,
681					'S_DISPLAY_SUBFORUM_LIMIT'	=> ($forum_data['display_subforum_limit']) ? true : false,
682					'S_DISPLAY_ON_INDEX'		=> ($forum_data['display_on_index']) ? true : false,
683					'S_PRUNE_ENABLE'			=> ($forum_data['enable_prune']) ? true : false,
684					'S_PRUNE_SHADOW_ENABLE'			=> ($forum_data['enable_shadow_prune']) ? true : false,
685					'S_FORUM_LINK_TRACK'		=> ($forum_data['forum_flags'] & FORUM_FLAG_LINK_TRACK) ? true : false,
686					'S_PRUNE_OLD_POLLS'			=> ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_POLL) ? true : false,
687					'S_PRUNE_ANNOUNCE'			=> ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_ANNOUNCE) ? true : false,
688					'S_PRUNE_STICKY'			=> ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_STICKY) ? true : false,
689					'S_DISPLAY_ACTIVE_TOPICS'	=> ($forum_data['forum_type'] == FORUM_POST) ? ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) : true,
690					'S_ENABLE_ACTIVE_TOPICS'	=> ($forum_data['forum_type'] == FORUM_CAT) ? ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) : false,
691					'S_ENABLE_POST_REVIEW'		=> ($forum_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) ? true : false,
692					'S_ENABLE_QUICK_REPLY'		=> ($forum_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) ? true : false,
693					'S_CAN_COPY_PERMISSIONS'	=> ($action != 'edit' || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth'))) ? true : false,
694				);
695
696				/**
697				* Modify forum template data before we display the form
698				*
699				* @event core.acp_manage_forums_display_form
700				* @var	string	action		Type of the action: add|edit
701				* @var	bool	update		Do we display the form only
702				*							or did the user press submit
703				* @var	int		forum_id	When editing: the forum id,
704				*							when creating: the parent forum id
705				* @var	array	row			Array with current forum data
706				*							empty when creating new forum
707				* @var	array	forum_data	Array with new forum data
708				* @var	string	parents_list	List of parent options
709				* @var	array	errors		Array of errors, if you add errors
710				*					ensure to update the template variables
711				*					S_ERROR and ERROR_MSG to display it
712				* @var	array	template_data	Array with new forum data
713				* @since 3.1.0-a1
714				*/
715				$vars = array(
716					'action',
717					'update',
718					'forum_id',
719					'row',
720					'forum_data',
721					'parents_list',
722					'errors',
723					'template_data',
724				);
725				extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_display_form', compact($vars)));
726
727				$template->assign_vars($template_data);
728
729				return;
730
731			break;
732
733			case 'delete':
734
735				if (!$forum_id)
736				{
737					trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
738				}
739
740				$forum_data = $this->get_forum_info($forum_id);
741
742				$subforums_id = array();
743				$subforums = get_forum_branch($forum_id, 'children');
744
745				foreach ($subforums as $row)
746				{
747					$subforums_id[] = $row['forum_id'];
748				}
749
750				$forums_list = make_forum_select($forum_data['parent_id'], $subforums_id);
751
752				$sql = 'SELECT forum_id
753					FROM ' . FORUMS_TABLE . '
754					WHERE forum_type = ' . FORUM_POST . "
755						AND forum_id <> $forum_id";
756				$result = $db->sql_query_limit($sql, 1);
757
758				if ($db->sql_fetchrow($result))
759				{
760					$template->assign_vars(array(
761						'S_MOVE_FORUM_OPTIONS'		=> make_forum_select($forum_data['parent_id'], $subforums_id, false, true)) // , false, true, false???
762					);
763				}
764				$db->sql_freeresult($result);
765
766				$parent_id = ($this->parent_id == $forum_id) ? 0 : $this->parent_id;
767
768				$template->assign_vars(array(
769					'S_DELETE_FORUM'		=> true,
770					'U_ACTION'				=> $this->u_action . "&amp;parent_id={$parent_id}&amp;action=delete&amp;f=$forum_id",
771					'U_BACK'				=> $this->u_action . '&amp;parent_id=' . $this->parent_id,
772
773					'FORUM_NAME'			=> $forum_data['forum_name'],
774					'S_FORUM_POST'			=> ($forum_data['forum_type'] == FORUM_POST) ? true : false,
775					'S_FORUM_LINK'			=> ($forum_data['forum_type'] == FORUM_LINK) ? true : false,
776					'S_HAS_SUBFORUMS'		=> ($forum_data['right_id'] - $forum_data['left_id'] > 1) ? true : false,
777					'S_FORUMS_LIST'			=> $forums_list,
778					'S_ERROR'				=> (count($errors)) ? true : false,
779					'ERROR_MSG'				=> (count($errors)) ? implode('<br />', $errors) : '')
780				);
781
782				return;
783			break;
784
785			case 'copy_perm':
786				$forum_perm_from = $request->variable('forum_perm_from', 0);
787
788				// Copy permissions?
789				if (!empty($forum_perm_from) && $forum_perm_from != $forum_id)
790				{
791					copy_forum_permissions($forum_perm_from, $forum_id, true);
792					phpbb_cache_moderators($db, $cache, $auth);
793					$auth->acl_clear_prefetch();
794					$cache->destroy('sql', FORUMS_TABLE);
795
796					$acl_url = '&amp;mode=setting_forum_local&amp;forum_id[]=' . $forum_id;
797
798					$message = $user->lang['FORUM_UPDATED'];
799
800					// Redirect to permissions
801					if ($auth->acl_get('a_fauth'))
802					{
803						$message .= '<br /><br />' . sprintf($user->lang['REDIRECT_ACL'], '<a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url) . '">', '</a>');
804					}
805
806					trigger_error($message . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
807				}
808
809			break;
810		}
811
812		// Default management page
813		if (!$this->parent_id)
814		{
815			$navigation = $user->lang['FORUM_INDEX'];
816		}
817		else
818		{
819			$navigation = '<a href="' . $this->u_action . '">' . $user->lang['FORUM_INDEX'] . '</a>';
820
821			$forums_nav = get_forum_branch($this->parent_id, 'parents', 'descending');
822			foreach ($forums_nav as $row)
823			{
824				if ($row['forum_id'] == $this->parent_id)
825				{
826					$navigation .= ' -&gt; ' . $row['forum_name'];
827				}
828				else
829				{
830					$navigation .= ' -&gt; <a href="' . $this->u_action . '&amp;parent_id=' . $row['forum_id'] . '">' . $row['forum_name'] . '</a>';
831				}
832			}
833		}
834
835		// Jumpbox
836		$forum_box = make_forum_select($this->parent_id, false, false, false, false); //make_forum_select($this->parent_id);
837
838		if ($action == 'sync' || $action == 'sync_forum')
839		{
840			$template->assign_var('S_RESYNCED', true);
841		}
842
843		$sql = 'SELECT *
844			FROM ' . FORUMS_TABLE . "
845			WHERE parent_id = $this->parent_id
846			ORDER BY left_id";
847		$result = $db->sql_query($sql);
848
849		$rowset = array();
850		while ($row = $db->sql_fetchrow($result))
851		{
852			$rowset[(int) $row['forum_id']] = $row;
853		}
854		$db->sql_freeresult($result);
855
856		/**
857		* Modify the forum list data
858		*
859		* @event core.acp_manage_forums_modify_forum_list
860		* @var	array	rowset	Array with the forums list data
861		* @since 3.1.10-RC1
862		*/
863		$vars = array('rowset');
864		extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_modify_forum_list', compact($vars)));
865
866		if (!empty($rowset))
867		{
868			foreach ($rowset as $row)
869			{
870				$forum_type = $row['forum_type'];
871
872				if ($row['forum_status'] == ITEM_LOCKED)
873				{
874					$folder_image = '<img src="images/icon_folder_lock.gif" alt="' . $user->lang['LOCKED'] . '" />';
875				}
876				else
877				{
878					switch ($forum_type)
879					{
880						case FORUM_LINK:
881							$folder_image = '<img src="images/icon_folder_link.gif" alt="' . $user->lang['LINK'] . '" />';
882						break;
883
884						default:
885							$folder_image = ($row['left_id'] + 1 != $row['right_id']) ? '<img src="images/icon_subfolder.gif" alt="' . $user->lang['SUBFORUM'] . '" />' : '<img src="images/icon_folder.gif" alt="' . $user->lang['FOLDER'] . '" />';
886						break;
887					}
888				}
889
890				$url = $this->u_action . "&amp;parent_id=$this->parent_id&amp;f={$row['forum_id']}";
891
892				$template->assign_block_vars('forums', array(
893					'FOLDER_IMAGE'		=> $folder_image,
894					'FORUM_IMAGE'		=> ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="" />' : '',
895					'FORUM_IMAGE_SRC'	=> ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '',
896					'FORUM_NAME'		=> $row['forum_name'],
897					'FORUM_DESCRIPTION'	=> generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']),
898					'FORUM_TOPICS'		=> $row['forum_topics_approved'],
899					'FORUM_POSTS'		=> $row['forum_posts_approved'],
900
901					'S_FORUM_LINK'		=> ($forum_type == FORUM_LINK) ? true : false,
902					'S_FORUM_POST'		=> ($forum_type == FORUM_POST) ? true : false,
903
904					'U_FORUM'			=> $this->u_action . '&amp;parent_id=' . $row['forum_id'],
905					'U_MOVE_UP'			=> $url . '&amp;action=move_up',
906					'U_MOVE_DOWN'		=> $url . '&amp;action=move_down',
907					'U_EDIT'			=> $url . '&amp;action=edit',
908					'U_DELETE'			=> $url . '&amp;action=delete',
909					'U_SYNC'			=> $url . '&amp;action=sync')
910				);
911			}
912		}
913		else if ($this->parent_id)
914		{
915			$row = $this->get_forum_info($this->parent_id);
916
917			$url = $this->u_action . '&amp;parent_id=' . $this->parent_id . '&amp;f=' . $row['forum_id'];
918
919			$template->assign_vars(array(
920				'S_NO_FORUMS'		=> true,
921
922				'U_EDIT'			=> $url . '&amp;action=edit',
923				'U_DELETE'			=> $url . '&amp;action=delete',
924				'U_SYNC'			=> $url . '&amp;action=sync')
925			);
926		}
927		unset($rowset);
928
929		$template->assign_vars(array(
930			'ERROR_MSG'		=> (count($errors)) ? implode('<br />', $errors) : '',
931			'NAVIGATION'	=> $navigation,
932			'FORUM_BOX'		=> $forum_box,
933			'U_SEL_ACTION'	=> $this->u_action,
934			'U_ACTION'		=> $this->u_action . '&amp;parent_id=' . $this->parent_id,
935
936			'U_PROGRESS_BAR'	=> $this->u_action . '&amp;action=progress_bar',
937			'UA_PROGRESS_BAR'	=> addslashes($this->u_action . '&amp;action=progress_bar'),
938		));
939	}
940
941	/**
942	* Get forum details
943	*/
944	function get_forum_info($forum_id)
945	{
946		global $db;
947
948		$sql = 'SELECT *
949			FROM ' . FORUMS_TABLE . "
950			WHERE forum_id = $forum_id";
951		$result = $db->sql_query($sql);
952		$row = $db->sql_fetchrow($result);
953		$db->sql_freeresult($result);
954
955		if (!$row)
956		{
957			trigger_error("Forum #$forum_id does not exist", E_USER_ERROR);
958		}
959
960		return $row;
961	}
962
963	/**
964	* Update forum data
965	*/
966	function update_forum_data(&$forum_data_ary)
967	{
968		global $db, $user, $cache, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $phpbb_log, $request;
969
970		$errors = array();
971
972		$forum_data = $forum_data_ary;
973		/**
974		* Validate the forum data before we create/update the forum
975		*
976		* @event core.acp_manage_forums_validate_data
977		* @var	array	forum_data	Array with new forum data
978		* @var	array	errors		Array of errors, should be strings and not
979		*							language key.
980		* @since 3.1.0-a1
981		*/
982		$vars = array('forum_data', 'errors');
983		extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_validate_data', compact($vars)));
984		$forum_data_ary = $forum_data;
985		unset($forum_data);
986
987		if ($forum_data_ary['forum_name'] == '')
988		{
989			$errors[] = $user->lang['FORUM_NAME_EMPTY'];
990		}
991
992		/**
993		 * Replace Emojis and other 4bit UTF-8 chars not allowed by MySql to UCR / NCR.
994		 * Using their Numeric Character Reference's Hexadecimal notation.
995		 */
996		$forum_data_ary['forum_name'] = utf8_encode_ucr($forum_data_ary['forum_name']);
997
998		/**
999		 * This should never happen again.
1000		 * Leaving the fallback here just in case there will be the need of it.
1001		 */
1002		if (preg_match_all('/[\x{10000}-\x{10FFFF}]/u', $forum_data_ary['forum_name'], $matches))
1003		{
1004			$character_list = implode('<br>', $matches[0]);
1005
1006			$errors[] = $user->lang('FORUM_NAME_EMOJI', $character_list);
1007		}
1008
1009		if (utf8_strlen($forum_data_ary['forum_desc']) > 4000)
1010		{
1011			$errors[] = $user->lang['FORUM_DESC_TOO_LONG'];
1012		}
1013
1014		if (utf8_strlen($forum_data_ary['forum_rules']) > 4000)
1015		{
1016			$errors[] = $user->lang['FORUM_RULES_TOO_LONG'];
1017		}
1018
1019		if ($forum_data_ary['forum_password'] || $forum_data_ary['forum_password_confirm'])
1020		{
1021			if ($forum_data_ary['forum_password'] != $forum_data_ary['forum_password_confirm'])
1022			{
1023				$forum_data_ary['forum_password'] = $forum_data_ary['forum_password_confirm'] = '';
1024				$errors[] = $user->lang['FORUM_PASSWORD_MISMATCH'];
1025			}
1026		}
1027
1028		if ($forum_data_ary['prune_days'] < 0 || $forum_data_ary['prune_viewed'] < 0 || $forum_data_ary['prune_freq'] < 0)
1029		{
1030			$forum_data_ary['prune_days'] = $forum_data_ary['prune_viewed'] = $forum_data_ary['prune_freq'] = 0;
1031			$errors[] = $user->lang['FORUM_DATA_NEGATIVE'];
1032		}
1033
1034		$range_test_ary = array(
1035			array('lang' => 'FORUM_TOPICS_PAGE', 'value' => $forum_data_ary['forum_topics_per_page'], 'column_type' => 'USINT:0'),
1036		);
1037
1038		if (!empty($forum_data_ary['forum_image']) && !file_exists($phpbb_root_path . $forum_data_ary['forum_image']))
1039		{
1040			$errors[] = $user->lang['FORUM_IMAGE_NO_EXIST'];
1041		}
1042
1043		validate_range($range_test_ary, $errors);
1044
1045		// Set forum flags
1046		// 1 = link tracking
1047		// 2 = prune old polls
1048		// 4 = prune announcements
1049		// 8 = prune stickies
1050		// 16 = show active topics
1051		// 32 = enable post review
1052		$forum_data_ary['forum_flags'] = 0;
1053		$forum_data_ary['forum_flags'] += ($forum_data_ary['forum_link_track']) ? FORUM_FLAG_LINK_TRACK : 0;
1054		$forum_data_ary['forum_flags'] += ($forum_data_ary['prune_old_polls']) ? FORUM_FLAG_PRUNE_POLL : 0;
1055		$forum_data_ary['forum_flags'] += ($forum_data_ary['prune_announce']) ? FORUM_FLAG_PRUNE_ANNOUNCE : 0;
1056		$forum_data_ary['forum_flags'] += ($forum_data_ary['prune_sticky']) ? FORUM_FLAG_PRUNE_STICKY : 0;
1057		$forum_data_ary['forum_flags'] += ($forum_data_ary['show_active']) ? FORUM_FLAG_ACTIVE_TOPICS : 0;
1058		$forum_data_ary['forum_flags'] += ($forum_data_ary['enable_post_review']) ? FORUM_FLAG_POST_REVIEW : 0;
1059		$forum_data_ary['forum_flags'] += ($forum_data_ary['enable_quick_reply']) ? FORUM_FLAG_QUICK_REPLY : 0;
1060
1061		// Unset data that are not database fields
1062		$forum_data_sql = $forum_data_ary;
1063
1064		unset($forum_data_sql['forum_link_track']);
1065		unset($forum_data_sql['prune_old_polls']);
1066		unset($forum_data_sql['prune_announce']);
1067		unset($forum_data_sql['prune_sticky']);
1068		unset($forum_data_sql['show_active']);
1069		unset($forum_data_sql['enable_post_review']);
1070		unset($forum_data_sql['enable_quick_reply']);
1071		unset($forum_data_sql['forum_password_confirm']);
1072
1073		// What are we going to do tonight Brain? The same thing we do everynight,
1074		// try to take over the world ... or decide whether to continue update
1075		// and if so, whether it's a new forum/cat/link or an existing one
1076		if (count($errors))
1077		{
1078			return $errors;
1079		}
1080
1081		// As we don't know the old password, it's kinda tricky to detect changes
1082		if ($forum_data_sql['forum_password_unset'])
1083		{
1084			$forum_data_sql['forum_password'] = '';
1085		}
1086		else if (empty($forum_data_sql['forum_password']))
1087		{
1088			unset($forum_data_sql['forum_password']);
1089		}
1090		else
1091		{
1092			// Instantiate passwords manager
1093			/* @var $passwords_manager \phpbb\passwords\manager */
1094			$passwords_manager = $phpbb_container->get('passwords.manager');
1095
1096			$forum_data_sql['forum_password'] = $passwords_manager->hash($forum_data_sql['forum_password']);
1097		}
1098		unset($forum_data_sql['forum_password_unset']);
1099
1100		$forum_data = $forum_data_ary;
1101		/**
1102		* Remove invalid values from forum_data_sql that should not be updated
1103		*
1104		* @event core.acp_manage_forums_update_data_before
1105		* @var	array	forum_data		Array with forum data
1106		* @var	array	forum_data_sql	Array with data we are going to update
1107		*						If forum_data_sql[forum_id] is set, we update
1108		*						that forum, otherwise a new one is created.
1109		* @since 3.1.0-a1
1110		*/
1111		$vars = array('forum_data', 'forum_data_sql');
1112		extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_update_data_before', compact($vars)));
1113		$forum_data_ary = $forum_data;
1114		unset($forum_data);
1115
1116		$is_new_forum = !isset($forum_data_sql['forum_id']);
1117
1118		if ($is_new_forum)
1119		{
1120			// no forum_id means we're creating a new forum
1121			unset($forum_data_sql['type_action']);
1122
1123			if ($forum_data_sql['parent_id'])
1124			{
1125				$sql = 'SELECT left_id, right_id, forum_type
1126					FROM ' . FORUMS_TABLE . '
1127					WHERE forum_id = ' . $forum_data_sql['parent_id'];
1128				$result = $db->sql_query($sql);
1129				$row = $db->sql_fetchrow($result);
1130				$db->sql_freeresult($result);
1131
1132				if (!$row)
1133				{
1134					trigger_error($user->lang['PARENT_NOT_EXIST'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
1135				}
1136
1137				if ($row['forum_type'] == FORUM_LINK)
1138				{
1139					$errors[] = $user->lang['PARENT_IS_LINK_FORUM'];
1140					return $errors;
1141				}
1142
1143				$sql = 'UPDATE ' . FORUMS_TABLE . '
1144					SET left_id = left_id + 2, right_id = right_id + 2
1145					WHERE left_id > ' . $row['right_id'];
1146				$db->sql_query($sql);
1147
1148				$sql = 'UPDATE ' . FORUMS_TABLE . '
1149					SET right_id = right_id + 2
1150					WHERE ' . $row['left_id'] . ' BETWEEN left_id AND right_id';
1151				$db->sql_query($sql);
1152
1153				$forum_data_sql['left_id'] = $row['right_id'];
1154				$forum_data_sql['right_id'] = $row['right_id'] + 1;
1155			}
1156			else
1157			{
1158				$sql = 'SELECT MAX(right_id) AS right_id
1159					FROM ' . FORUMS_TABLE;
1160				$result = $db->sql_query($sql);
1161				$row = $db->sql_fetchrow($result);
1162				$db->sql_freeresult($result);
1163
1164				$forum_data_sql['left_id'] = $row['right_id'] + 1;
1165				$forum_data_sql['right_id'] = $row['right_id'] + 2;
1166			}
1167
1168			$sql = 'INSERT INTO ' . FORUMS_TABLE . ' ' . $db->sql_build_array('INSERT', $forum_data_sql);
1169			$db->sql_query($sql);
1170
1171			$forum_data_ary['forum_id'] = $db->sql_nextid();
1172
1173			$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_ADD', false, array($forum_data_ary['forum_name']));
1174		}
1175		else
1176		{
1177			$row = $this->get_forum_info($forum_data_sql['forum_id']);
1178
1179			if ($row['forum_type'] == FORUM_POST && $row['forum_type'] != $forum_data_sql['forum_type'])
1180			{
1181				// Has subforums and want to change into a link?
1182				if ($row['right_id'] - $row['left_id'] > 1 && $forum_data_sql['forum_type'] == FORUM_LINK)
1183				{
1184					$errors[] = $user->lang['FORUM_WITH_SUBFORUMS_NOT_TO_LINK'];
1185					return $errors;
1186				}
1187
1188				// we're turning a postable forum into a non-postable forum
1189				if ($forum_data_sql['type_action'] == 'move')
1190				{
1191					$to_forum_id = $request->variable('to_forum_id', 0);
1192
1193					if ($to_forum_id)
1194					{
1195						$errors = $this->move_forum_content($forum_data_sql['forum_id'], $to_forum_id);
1196					}
1197					else
1198					{
1199						return array($user->lang['NO_DESTINATION_FORUM']);
1200					}
1201				}
1202				else if ($forum_data_sql['type_action'] == 'delete')
1203				{
1204					$errors = $this->delete_forum_content($forum_data_sql['forum_id']);
1205				}
1206				else
1207				{
1208					return array($user->lang['NO_FORUM_ACTION']);
1209				}
1210
1211				$forum_data_sql['forum_posts_approved'] = $forum_data_sql['forum_posts_unapproved'] = $forum_data_sql['forum_posts_softdeleted'] = $forum_data_sql['forum_topics_approved'] = $forum_data_sql['forum_topics_unapproved'] = $forum_data_sql['forum_topics_softdeleted'] = 0;
1212				$forum_data_sql['forum_last_post_id'] = $forum_data_sql['forum_last_poster_id'] = $forum_data_sql['forum_last_post_time'] = 0;
1213				$forum_data_sql['forum_last_poster_name'] = $forum_data_sql['forum_last_poster_colour'] = '';
1214			}
1215			else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_LINK)
1216			{
1217				// Has subforums?
1218				if ($row['right_id'] - $row['left_id'] > 1)
1219				{
1220					// We are turning a category into a link - but need to decide what to do with the subforums.
1221					$action_subforums = $request->variable('action_subforums', '');
1222					$subforums_to_id = $request->variable('subforums_to_id', 0);
1223
1224					if ($action_subforums == 'delete')
1225					{
1226						$rows = get_forum_branch($row['forum_id'], 'children', 'descending', false);
1227
1228						foreach ($rows as $_row)
1229						{
1230							// Do not remove the forum id we are about to change. ;)
1231							if ($_row['forum_id'] == $row['forum_id'])
1232							{
1233								continue;
1234							}
1235
1236							$forum_ids[] = $_row['forum_id'];
1237							$errors = array_merge($errors, $this->delete_forum_content($_row['forum_id']));
1238						}
1239
1240						if (count($errors))
1241						{
1242							return $errors;
1243						}
1244
1245						if (count($forum_ids))
1246						{
1247							$sql = 'DELETE FROM ' . FORUMS_TABLE . '
1248								WHERE ' . $db->sql_in_set('forum_id', $forum_ids);
1249							$db->sql_query($sql);
1250
1251							$sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
1252								WHERE ' . $db->sql_in_set('forum_id', $forum_ids);
1253							$db->sql_query($sql);
1254
1255							$sql = 'DELETE FROM ' . ACL_USERS_TABLE . '
1256								WHERE ' . $db->sql_in_set('forum_id', $forum_ids);
1257							$db->sql_query($sql);
1258
1259							// Delete forum ids from extension groups table
1260							$sql = 'SELECT group_id, allowed_forums
1261								FROM ' . EXTENSION_GROUPS_TABLE;
1262							$result = $db->sql_query($sql);
1263
1264							while ($_row = $db->sql_fetchrow($result))
1265							{
1266								if (!$_row['allowed_forums'])
1267								{
1268									continue;
1269								}
1270
1271								$allowed_forums = unserialize(trim($_row['allowed_forums']));
1272								$allowed_forums = array_diff($allowed_forums, $forum_ids);
1273
1274								$sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . "
1275									SET allowed_forums = '" . ((count($allowed_forums)) ? serialize($allowed_forums) : '') . "'
1276									WHERE group_id = {$_row['group_id']}";
1277								$db->sql_query($sql);
1278							}
1279							$db->sql_freeresult($result);
1280
1281							$cache->destroy('_extensions');
1282						}
1283					}
1284					else if ($action_subforums == 'move')
1285					{
1286						if (!$subforums_to_id)
1287						{
1288							return array($user->lang['NO_DESTINATION_FORUM']);
1289						}
1290
1291						$sql = 'SELECT forum_name
1292							FROM ' . FORUMS_TABLE . '
1293							WHERE forum_id = ' . $subforums_to_id;
1294						$result = $db->sql_query($sql);
1295						$_row = $db->sql_fetchrow($result);
1296						$db->sql_freeresult($result);
1297
1298						if (!$_row)
1299						{
1300							return array($user->lang['NO_FORUM']);
1301						}
1302
1303						$sql = 'SELECT forum_id
1304							FROM ' . FORUMS_TABLE . "
1305							WHERE parent_id = {$row['forum_id']}";
1306						$result = $db->sql_query($sql);
1307
1308						while ($_row = $db->sql_fetchrow($result))
1309						{
1310							$this->move_forum($_row['forum_id'], $subforums_to_id);
1311						}
1312						$db->sql_freeresult($result);
1313
1314						$sql = 'UPDATE ' . FORUMS_TABLE . "
1315							SET parent_id = $subforums_to_id
1316							WHERE parent_id = {$row['forum_id']}";
1317						$db->sql_query($sql);
1318					}
1319
1320					// Adjust the left/right id
1321					$sql = 'UPDATE ' . FORUMS_TABLE . '
1322						SET right_id = left_id + 1
1323						WHERE forum_id = ' . $row['forum_id'];
1324					$db->sql_query($sql);
1325				}
1326			}
1327			else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_POST)
1328			{
1329				// Changing a category to a forum? Reset the data (you can't post directly in a cat, you must use a forum)
1330				$forum_data_sql['forum_posts_approved'] = 0;
1331				$forum_data_sql['forum_posts_unapproved'] = 0;
1332				$forum_data_sql['forum_posts_softdeleted'] = 0;
1333				$forum_data_sql['forum_topics_approved'] = 0;
1334				$forum_data_sql['forum_topics_unapproved'] = 0;
1335				$forum_data_sql['forum_topics_softdeleted'] = 0;
1336				$forum_data_sql['forum_last_post_id'] = 0;
1337				$forum_data_sql['forum_last_post_subject'] = '';
1338				$forum_data_sql['forum_last_post_time'] = 0;
1339				$forum_data_sql['forum_last_poster_id'] = 0;
1340				$forum_data_sql['forum_last_poster_name'] = '';
1341				$forum_data_sql['forum_last_poster_colour'] = '';
1342			}
1343
1344			if (count($errors))
1345			{
1346				return $errors;
1347			}
1348
1349			if ($row['parent_id'] != $forum_data_sql['parent_id'])
1350			{
1351				if ($row['forum_id'] != $forum_data_sql['parent_id'])
1352				{
1353					$errors = $this->move_forum($forum_data_sql['forum_id'], $forum_data_sql['parent_id']);
1354				}
1355				else
1356				{
1357					$forum_data_sql['parent_id'] = $row['parent_id'];
1358				}
1359			}
1360
1361			if (count($errors))
1362			{
1363				return $errors;
1364			}
1365
1366			unset($forum_data_sql['type_action']);
1367
1368			if ($row['forum_name'] != $forum_data_sql['forum_name'])
1369			{
1370				// the forum name has changed, clear the parents list of all forums (for safety)
1371				$sql = 'UPDATE ' . FORUMS_TABLE . "
1372					SET forum_parents = ''";
1373				$db->sql_query($sql);
1374			}
1375
1376			// Setting the forum id to the forum id is not really received well by some dbs. ;)
1377			$forum_id = $forum_data_sql['forum_id'];
1378			unset($forum_data_sql['forum_id']);
1379
1380			$sql = 'UPDATE ' . FORUMS_TABLE . '
1381				SET ' . $db->sql_build_array('UPDATE', $forum_data_sql) . '
1382				WHERE forum_id = ' . $forum_id;
1383			$db->sql_query($sql);
1384
1385			// Add it back
1386			$forum_data_ary['forum_id'] = $forum_id;
1387
1388			$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_EDIT', false, array($forum_data_ary['forum_name']));
1389		}
1390
1391		$forum_data = $forum_data_ary;
1392		/**
1393		* Event after a forum was updated or created
1394		*
1395		* @event core.acp_manage_forums_update_data_after
1396		* @var	array	forum_data		Array with forum data
1397		* @var	array	forum_data_sql	Array with data we updated
1398		* @var	bool	is_new_forum	Did we create a forum or update one
1399		*								If you want to overwrite this value,
1400		*								ensure to set forum_data_sql[forum_id]
1401		* @var	array	errors		Array of errors, should be strings and not
1402		*							language key.
1403		* @since 3.1.0-a1
1404		*/
1405		$vars = array('forum_data', 'forum_data_sql', 'is_new_forum', 'errors');
1406		extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_update_data_after', compact($vars)));
1407		$forum_data_ary = $forum_data;
1408		unset($forum_data);
1409
1410		return $errors;
1411	}
1412
1413	/**
1414	* Move forum
1415	*/
1416	function move_forum($from_id, $to_id)
1417	{
1418		global $db, $user, $phpbb_dispatcher;
1419
1420		$errors = array();
1421
1422		// Check if we want to move to a parent with link type
1423		if ($to_id > 0)
1424		{
1425			$to_data = $this->get_forum_info($to_id);
1426
1427			if ($to_data['forum_type'] == FORUM_LINK)
1428			{
1429				$errors[] = $user->lang['PARENT_IS_LINK_FORUM'];
1430			}
1431		}
1432
1433		/**
1434		* Event when we move all children of one forum to another
1435		*
1436		* This event may be triggered, when a forum is deleted
1437		*
1438		* @event core.acp_manage_forums_move_children
1439		* @var	int		from_id		Id of the current parent forum
1440		* @var	int		to_id		Id of the new parent forum
1441		* @var	array	errors		Array of errors, should be strings and not
1442		*							language key.
1443		* @since 3.1.0-a1
1444		*/
1445		$vars = array('from_id', 'to_id', 'errors');
1446		extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_children', compact($vars)));
1447
1448		// Return if there were errors
1449		if (!empty($errors))
1450		{
1451			return $errors;
1452		}
1453
1454		$db->sql_transaction('begin');
1455
1456		$moved_forums = get_forum_branch($from_id, 'children', 'descending');
1457		$from_data = $moved_forums[0];
1458		$diff = count($moved_forums) * 2;
1459
1460		$moved_ids = array();
1461		for ($i = 0, $size = count($moved_forums); $i < $size; ++$i)
1462		{
1463			$moved_ids[] = $moved_forums[$i]['forum_id'];
1464		}
1465
1466		// Resync parents
1467		$sql = 'UPDATE ' . FORUMS_TABLE . "
1468			SET right_id = right_id - $diff, forum_parents = ''
1469			WHERE left_id < " . $from_data['right_id'] . "
1470				AND right_id > " . $from_data['right_id'];
1471		$db->sql_query($sql);
1472
1473		// Resync righthand side of tree
1474		$sql = 'UPDATE ' . FORUMS_TABLE . "
1475			SET left_id = left_id - $diff, right_id = right_id - $diff, forum_parents = ''
1476			WHERE left_id > " . $from_data['right_id'];
1477		$db->sql_query($sql);
1478
1479		if ($to_id > 0)
1480		{
1481			// Retrieve $to_data again, it may have been changed...
1482			$to_data = $this->get_forum_info($to_id);
1483
1484			// Resync new parents
1485			$sql = 'UPDATE ' . FORUMS_TABLE . "
1486				SET right_id = right_id + $diff, forum_parents = ''
1487				WHERE " . $to_data['right_id'] . ' BETWEEN left_id AND right_id
1488					AND ' . $db->sql_in_set('forum_id', $moved_ids, true);
1489			$db->sql_query($sql);
1490
1491			// Resync the righthand side of the tree
1492			$sql = 'UPDATE ' . FORUMS_TABLE . "
1493				SET left_id = left_id + $diff, right_id = right_id + $diff, forum_parents = ''
1494				WHERE left_id > " . $to_data['right_id'] . '
1495					AND ' . $db->sql_in_set('forum_id', $moved_ids, true);
1496			$db->sql_query($sql);
1497
1498			// Resync moved branch
1499			$to_data['right_id'] += $diff;
1500
1501			if ($to_data['right_id'] > $from_data['right_id'])
1502			{
1503				$diff = '+ ' . ($to_data['right_id'] - $from_data['right_id'] - 1);
1504			}
1505			else
1506			{
1507				$diff = '- ' . abs($to_data['right_id'] - $from_data['right_id'] - 1);
1508			}
1509		}
1510		else
1511		{
1512			$sql = 'SELECT MAX(right_id) AS right_id
1513				FROM ' . FORUMS_TABLE . '
1514				WHERE ' . $db->sql_in_set('forum_id', $moved_ids, true);
1515			$result = $db->sql_query($sql);
1516			$row = $db->sql_fetchrow($result);
1517			$db->sql_freeresult($result);
1518
1519			$diff = '+ ' . ($row['right_id'] - $from_data['left_id'] + 1);
1520		}
1521
1522		$sql = 'UPDATE ' . FORUMS_TABLE . "
1523			SET left_id = left_id $diff, right_id = right_id $diff, forum_parents = ''
1524			WHERE " . $db->sql_in_set('forum_id', $moved_ids);
1525		$db->sql_query($sql);
1526
1527		$db->sql_transaction('commit');
1528
1529		return $errors;
1530	}
1531
1532	/**
1533	* Move forum content from one to another forum
1534	*/
1535	function move_forum_content($from_id, $to_id, $sync = true)
1536	{
1537		global $db, $phpbb_dispatcher;
1538
1539		$errors = array();
1540
1541		/**
1542		* Event when we move content from one forum to another
1543		*
1544		* @event core.acp_manage_forums_move_content
1545		* @var	int		from_id		Id of the current parent forum
1546		* @var	int		to_id		Id of the new parent forum
1547		* @var	bool	sync		Shall we sync the "to"-forum's data
1548		* @var	array	errors		Array of errors, should be strings and not
1549		*							language key. If this array is not empty,
1550		*							The content will not be moved.
1551		* @since 3.1.0-a1
1552		*/
1553		$vars = array('from_id', 'to_id', 'sync', 'errors');
1554		extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_content', compact($vars)));
1555
1556		// Return if there were errors
1557		if (!empty($errors))
1558		{
1559			return $errors;
1560		}
1561
1562		$table_ary = array(LOG_TABLE, POSTS_TABLE, TOPICS_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE);
1563
1564		/**
1565		 * Perform additional actions before move forum content
1566		 *
1567		 * @event core.acp_manage_forums_move_content_sql_before
1568		 * @var	array	table_ary	Array of tables from which forum_id will be updated
1569		 * @since 3.2.4-RC1
1570		 */
1571		$vars = array('table_ary');
1572		extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_content_sql_before', compact($vars)));
1573
1574		foreach ($table_ary as $table)
1575		{
1576			$sql = "UPDATE $table
1577				SET forum_id = $to_id
1578				WHERE forum_id = $from_id";
1579			$db->sql_query($sql);
1580		}
1581		unset($table_ary);
1582
1583		$table_ary = array(FORUMS_ACCESS_TABLE, FORUMS_TRACK_TABLE, FORUMS_WATCH_TABLE, MODERATOR_CACHE_TABLE);
1584
1585		foreach ($table_ary as $table)
1586		{
1587			$sql = "DELETE FROM $table
1588				WHERE forum_id = $from_id";
1589			$db->sql_query($sql);
1590		}
1591
1592		/**
1593		 * Event when content has been moved from one forum to another
1594		 *
1595		 * @event core.acp_manage_forums_move_content_after
1596		 * @var	int		from_id		Id of the current parent forum
1597		 * @var	int		to_id		Id of the new parent forum
1598		 * @var	bool	sync		Shall we sync the "to"-forum's data
1599		 *
1600		 * @since 3.2.9-RC1
1601		 */
1602		$vars = array('from_id', 'to_id', 'sync');
1603		extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_content_after', compact($vars)));
1604
1605		if ($sync)
1606		{
1607			// Delete ghost topics that link back to the same forum then resync counters
1608			sync('topic_moved');
1609			sync('forum', 'forum_id', $to_id, false, true);
1610		}
1611
1612		return array();
1613	}
1614
1615	/**
1616	* Remove complete forum
1617	*/
1618	function delete_forum($forum_id, $action_posts = 'delete', $action_subforums = 'delete', $posts_to_id = 0, $subforums_to_id = 0)
1619	{
1620		global $db, $user, $cache, $phpbb_log;
1621
1622		$forum_data = $this->get_forum_info($forum_id);
1623
1624		$errors = array();
1625		$log_action_posts = $log_action_forums = $posts_to_name = $subforums_to_name = '';
1626		$forum_ids = array($forum_id);
1627
1628		if ($action_posts == 'delete')
1629		{
1630			$log_action_posts = 'POSTS';
1631			$errors = array_merge($errors, $this->delete_forum_content($forum_id));
1632		}
1633		else if ($action_posts == 'move')
1634		{
1635			if (!$posts_to_id)
1636			{
1637				$errors[] = $user->lang['NO_DESTINATION_FORUM'];
1638			}
1639			else
1640			{
1641				$log_action_posts = 'MOVE_POSTS';
1642
1643				$sql = 'SELECT forum_name
1644					FROM ' . FORUMS_TABLE . '
1645					WHERE forum_id = ' . $posts_to_id;
1646				$result = $db->sql_query($sql);
1647				$row = $db->sql_fetchrow($result);
1648				$db->sql_freeresult($result);
1649
1650				if (!$row)
1651				{
1652					$errors[] = $user->lang['NO_FORUM'];
1653				}
1654				else
1655				{
1656					$posts_to_name = $row['forum_name'];
1657					$errors = array_merge($errors, $this->move_forum_content($forum_id, $posts_to_id));
1658				}
1659			}
1660		}
1661
1662		if (count($errors))
1663		{
1664			return $errors;
1665		}
1666
1667		if ($action_subforums == 'delete')
1668		{
1669			$log_action_forums = 'FORUMS';
1670			$rows = get_forum_branch($forum_id, 'children', 'descending', false);
1671
1672			foreach ($rows as $row)
1673			{
1674				$forum_ids[] = $row['forum_id'];
1675				$errors = array_merge($errors, $this->delete_forum_content($row['forum_id']));
1676			}
1677
1678			if (count($errors))
1679			{
1680				return $errors;
1681			}
1682
1683			$diff = count($forum_ids) * 2;
1684
1685			$sql = 'DELETE FROM ' . FORUMS_TABLE . '
1686				WHERE ' . $db->sql_in_set('forum_id', $forum_ids);
1687			$db->sql_query($sql);
1688
1689			$sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
1690				WHERE ' . $db->sql_in_set('forum_id', $forum_ids);
1691			$db->sql_query($sql);
1692
1693			$sql = 'DELETE FROM ' . ACL_USERS_TABLE . '
1694				WHERE ' . $db->sql_in_set('forum_id', $forum_ids);
1695			$db->sql_query($sql);
1696		}
1697		else if ($action_subforums == 'move')
1698		{
1699			if (!$subforums_to_id)
1700			{
1701				$errors[] = $user->lang['NO_DESTINATION_FORUM'];
1702			}
1703			else
1704			{
1705				$log_action_forums = 'MOVE_FORUMS';
1706
1707				$sql = 'SELECT forum_name
1708					FROM ' . FORUMS_TABLE . '
1709					WHERE forum_id = ' . $subforums_to_id;
1710				$result = $db->sql_query($sql);
1711				$row = $db->sql_fetchrow($result);
1712				$db->sql_freeresult($result);
1713
1714				if (!$row)
1715				{
1716					$errors[] = $user->lang['NO_FORUM'];
1717				}
1718				else
1719				{
1720					$subforums_to_name = $row['forum_name'];
1721
1722					$sql = 'SELECT forum_id
1723						FROM ' . FORUMS_TABLE . "
1724						WHERE parent_id = $forum_id";
1725					$result = $db->sql_query($sql);
1726
1727					while ($row = $db->sql_fetchrow($result))
1728					{
1729						$this->move_forum($row['forum_id'], $subforums_to_id);
1730					}
1731					$db->sql_freeresult($result);
1732
1733					// Grab new forum data for correct tree updating later
1734					$forum_data = $this->get_forum_info($forum_id);
1735
1736					$sql = 'UPDATE ' . FORUMS_TABLE . "
1737						SET parent_id = $subforums_to_id
1738						WHERE parent_id = $forum_id";
1739					$db->sql_query($sql);
1740
1741					$diff = 2;
1742					$sql = 'DELETE FROM ' . FORUMS_TABLE . "
1743						WHERE forum_id = $forum_id";
1744					$db->sql_query($sql);
1745
1746					$sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . "
1747						WHERE forum_id = $forum_id";
1748					$db->sql_query($sql);
1749
1750					$sql = 'DELETE FROM ' . ACL_USERS_TABLE . "
1751						WHERE forum_id = $forum_id";
1752					$db->sql_query($sql);
1753				}
1754			}
1755
1756			if (count($errors))
1757			{
1758				return $errors;
1759			}
1760		}
1761		else
1762		{
1763			$diff = 2;
1764			$sql = 'DELETE FROM ' . FORUMS_TABLE . "
1765				WHERE forum_id = $forum_id";
1766			$db->sql_query($sql);
1767
1768			$sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . "
1769				WHERE forum_id = $forum_id";
1770			$db->sql_query($sql);
1771
1772			$sql = 'DELETE FROM ' . ACL_USERS_TABLE . "
1773				WHERE forum_id = $forum_id";
1774			$db->sql_query($sql);
1775		}
1776
1777		// Resync tree
1778		$sql = 'UPDATE ' . FORUMS_TABLE . "
1779			SET right_id = right_id - $diff
1780			WHERE left_id < {$forum_data['right_id']} AND right_id > {$forum_data['right_id']}";
1781		$db->sql_query($sql);
1782
1783		$sql = 'UPDATE ' . FORUMS_TABLE . "
1784			SET left_id = left_id - $diff, right_id = right_id - $diff
1785			WHERE left_id > {$forum_data['right_id']}";
1786		$db->sql_query($sql);
1787
1788		// Delete forum ids from extension groups table
1789		$sql = 'SELECT group_id, allowed_forums
1790			FROM ' . EXTENSION_GROUPS_TABLE;
1791		$result = $db->sql_query($sql);
1792
1793		while ($row = $db->sql_fetchrow($result))
1794		{
1795			if (!$row['allowed_forums'])
1796			{
1797				continue;
1798			}
1799
1800			$allowed_forums = unserialize(trim($row['allowed_forums']));
1801			$allowed_forums = array_diff($allowed_forums, $forum_ids);
1802
1803			$sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . "
1804				SET allowed_forums = '" . ((count($allowed_forums)) ? serialize($allowed_forums) : '') . "'
1805				WHERE group_id = {$row['group_id']}";
1806			$db->sql_query($sql);
1807		}
1808		$db->sql_freeresult($result);
1809
1810		$cache->destroy('_extensions');
1811
1812		$log_action = implode('_', array($log_action_posts, $log_action_forums));
1813
1814		switch ($log_action)
1815		{
1816			case 'MOVE_POSTS_MOVE_FORUMS':
1817				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_MOVE_POSTS_MOVE_FORUMS', false, array($posts_to_name, $subforums_to_name, $forum_data['forum_name']));
1818			break;
1819
1820			case 'MOVE_POSTS_FORUMS':
1821				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_MOVE_POSTS_FORUMS', false, array($posts_to_name, $forum_data['forum_name']));
1822			break;
1823
1824			case 'POSTS_MOVE_FORUMS':
1825				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS_MOVE_FORUMS', false, array($subforums_to_name, $forum_data['forum_name']));
1826			break;
1827
1828			case '_MOVE_FORUMS':
1829				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_MOVE_FORUMS', false, array($subforums_to_name, $forum_data['forum_name']));
1830			break;
1831
1832			case 'MOVE_POSTS_':
1833				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_MOVE_POSTS', false, array($posts_to_name, $forum_data['forum_name']));
1834			break;
1835
1836			case 'POSTS_FORUMS':
1837				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS_FORUMS', false, array($forum_data['forum_name']));
1838			break;
1839
1840			case '_FORUMS':
1841				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_FORUMS', false, array($forum_data['forum_name']));
1842			break;
1843
1844			case 'POSTS_':
1845				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS', false, array($forum_data['forum_name']));
1846			break;
1847
1848			default:
1849				$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_FORUM', false, array($forum_data['forum_name']));
1850			break;
1851		}
1852
1853		return $errors;
1854	}
1855
1856	/**
1857	* Delete forum content
1858	*/
1859	function delete_forum_content($forum_id)
1860	{
1861		global $db, $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
1862
1863		include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
1864
1865		$db->sql_transaction('begin');
1866
1867		// Select then delete all attachments
1868		$sql = 'SELECT a.topic_id
1869			FROM ' . POSTS_TABLE . ' p, ' . ATTACHMENTS_TABLE . " a
1870			WHERE p.forum_id = $forum_id
1871				AND a.in_message = 0
1872				AND a.topic_id = p.topic_id";
1873		$result = $db->sql_query($sql);
1874
1875		$topic_ids = array();
1876		while ($row = $db->sql_fetchrow($result))
1877		{
1878			$topic_ids[] = $row['topic_id'];
1879		}
1880		$db->sql_freeresult($result);
1881
1882		/** @var \phpbb\attachment\manager $attachment_manager */
1883		$attachment_manager = $phpbb_container->get('attachment.manager');
1884		$attachment_manager->delete('topic', $topic_ids, false);
1885		unset($attachment_manager);
1886
1887		// Delete shadow topics pointing to topics in this forum
1888		delete_topic_shadows($forum_id);
1889
1890		// Before we remove anything we make sure we are able to adjust the post counts later. ;)
1891		$sql = 'SELECT poster_id
1892			FROM ' . POSTS_TABLE . '
1893			WHERE forum_id = ' . $forum_id . '
1894				AND post_postcount = 1
1895				AND post_visibility = ' . ITEM_APPROVED;
1896		$result = $db->sql_query($sql);
1897
1898		$post_counts = array();
1899		while ($row = $db->sql_fetchrow($result))
1900		{
1901			$post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1;
1902		}
1903		$db->sql_freeresult($result);
1904
1905		switch ($db->get_sql_layer())
1906		{
1907			case 'mysqli':
1908
1909				// Delete everything else and thank MySQL for offering multi-table deletion
1910				$tables_ary = array(
1911					SEARCH_WORDMATCH_TABLE	=> 'post_id',
1912					REPORTS_TABLE			=> 'post_id',
1913					WARNINGS_TABLE			=> 'post_id',
1914					BOOKMARKS_TABLE			=> 'topic_id',
1915					TOPICS_WATCH_TABLE		=> 'topic_id',
1916					TOPICS_POSTED_TABLE		=> 'topic_id',
1917					POLL_OPTIONS_TABLE		=> 'topic_id',
1918					POLL_VOTES_TABLE		=> 'topic_id',
1919				);
1920
1921				$sql = 'DELETE ' . POSTS_TABLE;
1922				$sql_using = "\nFROM " . POSTS_TABLE;
1923				$sql_where = "\nWHERE " . POSTS_TABLE . ".forum_id = $forum_id\n";
1924
1925				foreach ($tables_ary as $table => $field)
1926				{
1927					$sql .= ", $table ";
1928					$sql_using .= ", $table ";
1929					$sql_where .= "\nAND $table.$field = " . POSTS_TABLE . ".$field";
1930				}
1931
1932				$db->sql_query($sql . $sql_using . $sql_where);
1933
1934			break;
1935
1936			default:
1937
1938				// Delete everything else and curse your DB for not offering multi-table deletion
1939				$tables_ary = array(
1940					'post_id'	=>	array(
1941						SEARCH_WORDMATCH_TABLE,
1942						REPORTS_TABLE,
1943						WARNINGS_TABLE,
1944					),
1945
1946					'topic_id'	=>	array(
1947						BOOKMARKS_TABLE,
1948						TOPICS_WATCH_TABLE,
1949						TOPICS_POSTED_TABLE,
1950						POLL_OPTIONS_TABLE,
1951						POLL_VOTES_TABLE,
1952					)
1953				);
1954
1955				// Amount of rows we select and delete in one iteration.
1956				$batch_size = 500;
1957
1958				foreach ($tables_ary as $field => $tables)
1959				{
1960					$start = 0;
1961
1962					do
1963					{
1964						$sql = "SELECT $field
1965							FROM " . POSTS_TABLE . '
1966							WHERE forum_id = ' . $forum_id;
1967						$result = $db->sql_query_limit($sql, $batch_size, $start);
1968
1969						$ids = array();
1970						while ($row = $db->sql_fetchrow($result))
1971						{
1972							$ids[] = $row[$field];
1973						}
1974						$db->sql_freeresult($result);
1975
1976						if (count($ids))
1977						{
1978							$start += count($ids);
1979
1980							foreach ($tables as $table)
1981							{
1982								$db->sql_query("DELETE FROM $table WHERE " . $db->sql_in_set($field, $ids));
1983							}
1984						}
1985					}
1986					while (count($ids) == $batch_size);
1987				}
1988				unset($ids);
1989
1990			break;
1991		}
1992
1993		$table_ary = array(FORUMS_ACCESS_TABLE, FORUMS_TRACK_TABLE, FORUMS_WATCH_TABLE, LOG_TABLE, MODERATOR_CACHE_TABLE, POSTS_TABLE, TOPICS_TABLE, TOPICS_TRACK_TABLE);
1994
1995		/**
1996		 * Perform additional actions before forum content deletion
1997		 *
1998		 * @event core.delete_forum_content_before_query
1999		 * @var	array	table_ary	Array of tables from which all rows will be deleted that hold the forum_id
2000		 * @var	int		forum_id	the forum id
2001		 * @var	array	topic_ids	Array of the topic ids from the forum to be deleted
2002		 * @var	array	post_counts	Array of counts of posts in the forum, by poster_id
2003		 * @since 3.1.6-RC1
2004		 */
2005		$vars = array(
2006				'table_ary',
2007				'forum_id',
2008				'topic_ids',
2009				'post_counts',
2010		);
2011		extract($phpbb_dispatcher->trigger_event('core.delete_forum_content_before_query', compact($vars)));
2012
2013		foreach ($table_ary as $table)
2014		{
2015			$db->sql_query("DELETE FROM $table WHERE forum_id = $forum_id");
2016		}
2017
2018		// Set forum ids to 0
2019		$table_ary = array(DRAFTS_TABLE);
2020
2021		foreach ($table_ary as $table)
2022		{
2023			$db->sql_query("UPDATE $table SET forum_id = 0 WHERE forum_id = $forum_id");
2024		}
2025
2026		// Adjust users post counts
2027		if (count($post_counts))
2028		{
2029			foreach ($post_counts as $poster_id => $substract)
2030			{
2031				$sql = 'UPDATE ' . USERS_TABLE . '
2032					SET user_posts = 0
2033					WHERE user_id = ' . $poster_id . '
2034					AND user_posts < ' . $substract;
2035				$db->sql_query($sql);
2036
2037				$sql = 'UPDATE ' . USERS_TABLE . '
2038					SET user_posts = user_posts - ' . $substract . '
2039					WHERE user_id = ' . $poster_id . '
2040					AND user_posts >= ' . $substract;
2041				$db->sql_query($sql);
2042			}
2043		}
2044
2045		$db->sql_transaction('commit');
2046
2047		// Make sure the overall post/topic count is correct...
2048		$sql = 'SELECT COUNT(post_id) AS stat
2049			FROM ' . POSTS_TABLE . '
2050			WHERE post_visibility = ' . ITEM_APPROVED;
2051		$result = $db->sql_query($sql);
2052		$row = $db->sql_fetchrow($result);
2053		$db->sql_freeresult($result);
2054
2055		$config->set('num_posts', (int) $row['stat'], false);
2056
2057		$sql = 'SELECT COUNT(topic_id) AS stat
2058			FROM ' . TOPICS_TABLE . '
2059			WHERE topic_visibility = ' . ITEM_APPROVED;
2060		$result = $db->sql_query($sql);
2061		$row = $db->sql_fetchrow($result);
2062		$db->sql_freeresult($result);
2063
2064		$config->set('num_topics', (int) $row['stat'], false);
2065
2066		$sql = 'SELECT COUNT(attach_id) as stat
2067			FROM ' . ATTACHMENTS_TABLE;
2068		$result = $db->sql_query($sql);
2069		$row = $db->sql_fetchrow($result);
2070		$db->sql_freeresult($result);
2071
2072		$config->set('num_files', (int) $row['stat'], false);
2073
2074		$sql = 'SELECT SUM(filesize) as stat
2075			FROM ' . ATTACHMENTS_TABLE;
2076		$result = $db->sql_query($sql);
2077		$row = $db->sql_fetchrow($result);
2078		$db->sql_freeresult($result);
2079
2080		$config->set('upload_dir_size', (float) $row['stat'], false);
2081
2082		return array();
2083	}
2084
2085	/**
2086	* Move forum position by $steps up/down
2087	*/
2088	function move_forum_by($forum_row, $action = 'move_up', $steps = 1)
2089	{
2090		global $db;
2091
2092		/**
2093		* Fetch all the siblings between the module's current spot
2094		* and where we want to move it to. If there are less than $steps
2095		* siblings between the current spot and the target then the
2096		* module will move as far as possible
2097		*/
2098		$sql = 'SELECT forum_id, forum_name, left_id, right_id
2099			FROM ' . FORUMS_TABLE . "
2100			WHERE parent_id = {$forum_row['parent_id']}
2101				AND " . (($action == 'move_up') ? "right_id < {$forum_row['right_id']} ORDER BY right_id DESC" : "left_id > {$forum_row['left_id']} ORDER BY left_id ASC");
2102		$result = $db->sql_query_limit($sql, $steps);
2103
2104		$target = array();
2105		while ($row = $db->sql_fetchrow($result))
2106		{
2107			$target = $row;
2108		}
2109		$db->sql_freeresult($result);
2110
2111		if (!count($target))
2112		{
2113			// The forum is already on top or bottom
2114			return false;
2115		}
2116
2117		/**
2118		* $left_id and $right_id define the scope of the nodes that are affected by the move.
2119		* $diff_up and $diff_down are the values to substract or add to each node's left_id
2120		* and right_id in order to move them up or down.
2121		* $move_up_left and $move_up_right define the scope of the nodes that are moving
2122		* up. Other nodes in the scope of ($left_id, $right_id) are considered to move down.
2123		*/
2124		if ($action == 'move_up')
2125		{
2126			$left_id = $target['left_id'];
2127			$right_id = $forum_row['right_id'];
2128
2129			$diff_up = $forum_row['left_id'] - $target['left_id'];
2130			$diff_down = $forum_row['right_id'] + 1 - $forum_row['left_id'];
2131
2132			$move_up_left = $forum_row['left_id'];
2133			$move_up_right = $forum_row['right_id'];
2134		}
2135		else
2136		{
2137			$left_id = $forum_row['left_id'];
2138			$right_id = $target['right_id'];
2139
2140			$diff_up = $forum_row['right_id'] + 1 - $forum_row['left_id'];
2141			$diff_down = $target['right_id'] - $forum_row['right_id'];
2142
2143			$move_up_left = $forum_row['right_id'] + 1;
2144			$move_up_right = $target['right_id'];
2145		}
2146
2147		// Now do the dirty job
2148		$sql = 'UPDATE ' . FORUMS_TABLE . "
2149			SET left_id = left_id + CASE
2150				WHEN left_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
2151				ELSE {$diff_down}
2152			END,
2153			right_id = right_id + CASE
2154				WHEN right_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
2155				ELSE {$diff_down}
2156			END,
2157			forum_parents = ''
2158			WHERE
2159				left_id BETWEEN {$left_id} AND {$right_id}
2160				AND right_id BETWEEN {$left_id} AND {$right_id}";
2161		$db->sql_query($sql);
2162
2163		return $target['forum_name'];
2164	}
2165
2166	/**
2167	* Display progress bar for syncinc forums
2168	*/
2169	function display_progress_bar($start, $total)
2170	{
2171		global $template, $user;
2172
2173		adm_page_header($user->lang['SYNC_IN_PROGRESS']);
2174
2175		$template->set_filenames(array(
2176			'body'	=> 'progress_bar.html')
2177		);
2178
2179		$template->assign_vars(array(
2180			'L_PROGRESS'			=> $user->lang['SYNC_IN_PROGRESS'],
2181			'L_PROGRESS_EXPLAIN'	=> ($start && $total) ? sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $start, $total) : $user->lang['SYNC_IN_PROGRESS'])
2182		);
2183
2184		adm_page_footer();
2185	}
2186
2187	/**
2188	* Display copy permission page
2189	* Not used at the moment - we will have a look at it for 3.0.7
2190	*/
2191	function copy_permission_page($forum_data)
2192	{
2193		global $phpEx, $phpbb_admin_path, $template, $user;
2194
2195		$acl_url = '&amp;mode=setting_forum_local&amp;forum_id[]=' . $forum_data['forum_id'];
2196		$action = append_sid($this->u_action . "&amp;parent_id={$this->parent_id}&amp;f={$forum_data['forum_id']}&amp;action=copy_perm");
2197
2198		$l_acl = sprintf($user->lang['COPY_TO_ACL'], '<a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url) . '">', '</a>');
2199
2200		$this->tpl_name = 'acp_forums_copy_perm';
2201
2202		$template->assign_vars(array(
2203			'U_ACL'				=> append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url),
2204			'L_ACL_LINK'		=> $l_acl,
2205			'L_BACK_LINK'		=> adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id),
2206			'S_COPY_ACTION'		=> $action,
2207			'S_FORUM_OPTIONS'	=> make_forum_select($forum_data['parent_id'], $forum_data['forum_id'], false, false, false),
2208		));
2209	}
2210
2211}
2212