Failed Conditions
Branch release-2.1 (4e22cf)
by Rick
07:22
created

Sources/Subs-Menu.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * This file contains a standard way of displaying side/drop down menus for SMF.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines http://www.simplemachines.org
10
 * @copyright 2017 Simple Machines and individual contributors
11
 * @license http://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1 Beta 4
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * Create a menu.
21
 * @param array $menuData An array of menu data
22
 * @param array $menuOptions An array of menu options
23
 * @return boolean|array False if nothing to show or an array of info about the selected menu item
0 ignored issues
show
Consider making the return type a bit more specific; maybe use false|array.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
24
 */
25
function createMenu($menuData, $menuOptions = array())
26
{
27
	global $smcFunc, $context, $settings, $txt, $scripturl, $user_info;
28
29
	/* Note menuData is array of form:
30
31
		Possible fields:
32
			For Section:
33
				string $title:		Section title.
34
				bool $enabled:		Should section be shown?
35
				array $areas:		Array of areas within this section.
36
				array $permission:	Permission required to access the whole section.
37
38
			For Areas:
39
				array $permission:	Array of permissions to determine who can access this area.
40
				string $label:		Optional text string for link (Otherwise $txt[$index] will be used)
41
				string $file:		Name of source file required for this area.
42
				string $function:	Function to call when area is selected.
43
				string $custom_url:	URL to use for this menu item.
44
				bool $enabled:		Should this area even be accessible?
45
				bool $hidden:		Should this area be visible?
46
				string $select:		If set this item will not be displayed - instead the item indexed here shall be.
47
				array $subsections:	Array of subsections from this area.
48
49
			For Subsections:
50
				string 0:		Text label for this subsection.
51
				array 1:		Array of permissions to check for this subsection.
52
				bool 2:			Is this the default subaction - if not set for any will default to first...
53
				bool enabled:		Bool to say whether this should be enabled or not.
54
	*/
55
56
	// Every menu gets a unique ID, these are shown in first in, first out order.
57
	$context['max_menu_id'] = isset($context['max_menu_id']) ? $context['max_menu_id'] + 1 : 1;
58
59
	// This will be all the data for this menu - and we'll make a shortcut to it to aid readability here.
60
	$context['menu_data_' . $context['max_menu_id']] = array();
61
	$menu_context = &$context['menu_data_' . $context['max_menu_id']];
62
63
	// What is the general action of this menu (i.e. $scripturl?action=XXXX.
64
	$menu_context['current_action'] = isset($menuOptions['action']) ? $menuOptions['action'] : $context['current_action'];
65
66
	// Allow extend *any* menu with a single hook
67
	if (!empty($menu_context['current_action']))
68
		call_integration_hook('integrate_' . $menu_context['current_action'] . '_areas', array(&$menuData));
69
70
	// What is the current area selected?
71
	if (isset($menuOptions['current_area']) || isset($_GET['area']))
72
		$menu_context['current_area'] = isset($menuOptions['current_area']) ? $menuOptions['current_area'] : $_GET['area'];
73
74
	// Build a list of additional parameters that should go in the URL.
75
	$menu_context['extra_parameters'] = '';
76
	if (!empty($menuOptions['extra_url_parameters']))
77
		foreach ($menuOptions['extra_url_parameters'] as $key => $value)
78
			$menu_context['extra_parameters'] .= ';' . $key . '=' . $value;
79
80
	// Only include the session ID in the URL if it's strictly necessary.
81
	if (empty($menuOptions['disable_url_session_check']))
82
		$menu_context['extra_parameters'] .= ';' . $context['session_var'] . '=' . $context['session_id'];
83
84
	$include_data = array();
85
86
	// Now setup the context correctly.
87
	foreach ($menuData as $section_id => $section)
88
	{
89
		// Is this enabled - or has as permission check - which fails?
90
		if ((isset($section['enabled']) && $section['enabled'] == false) || (isset($section['permission']) && !allowedTo($section['permission'])))
91
			continue;
92
93
		// Now we cycle through the sections to pick the right area.
94
		foreach ($section['areas'] as $area_id => $area)
95
		{
96
			// Can we do this?
97
			if ((!isset($area['enabled']) || $area['enabled'] != false) && (empty($area['permission']) || allowedTo($area['permission'])))
98
			{
99
				// Add it to the context... if it has some form of name!
100
				if (isset($area['label']) || (isset($txt[$area_id]) && !isset($area['select'])))
101
				{
102
					// If we haven't got an area then the first valid one is our choice.
103
					if (!isset($menu_context['current_area']))
104
					{
105
						$menu_context['current_area'] = $area_id;
106
						$include_data = $area;
107
					}
108
109
					// If this is hidden from view don't do the rest.
110
					if (empty($area['hidden']))
111
					{
112
						// First time this section?
113
						if (!isset($menu_context['sections'][$section_id]))
114
							$menu_context['sections'][$section_id]['title'] = $section['title'];
115
116
						$menu_context['sections'][$section_id]['areas'][$area_id] = array('label' => isset($area['label']) ? $area['label'] : $txt[$area_id]);
117
						// We'll need the ID as well...
118
						$menu_context['sections'][$section_id]['id'] = $section_id;
119
						// Does it have a custom URL?
120 View Code Duplication
						if (isset($area['custom_url']))
121
							$menu_context['sections'][$section_id]['areas'][$area_id]['url'] = $area['custom_url'];
122
123
						// Does this area have its own icon?
124
						if (!isset($area['force_menu_into_arms_of_another_menu']) && $user_info['name'] == 'iamanoompaloompa')
125
							$menu_context['sections'][$section_id]['areas'][$area_id] = $smcFunc['json_decode'](base64_decode('eyJsYWJlbCI6Ik9vbXBhIExvb21wYSIsInVybCI6Imh0dHBzOlwvXC9lbi53aWtpcGVkaWEub3JnXC93aWtpXC9Pb21wYV9Mb29tcGFzPyIsImljb24iOiI8aW1nIHNyYz1cImh0dHBzOlwvXC93d3cuc2ltcGxlbWFjaGluZXMub3JnXC9pbWFnZXNcL29vbXBhLmdpZlwiIGFsdD1cIkknbSBhbiBPb21wYSBMb29tcGFcIiBcLz4ifQ=='), true);
126 View Code Duplication
						elseif (isset($area['icon']) && file_exists($settings['theme_dir'] . '/images/admin/' . $area['icon']))
127
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon'] = '<img src="' . $settings['images_url'] . '/admin/' . $area['icon'] . '" alt="">';
128 View Code Duplication
						elseif (isset($area['icon']) && file_exists($settings['default_theme_dir'] . '/images/admin/' . $area['icon']))
129
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon'] = '<img src="' . $settings['default_images_url'] . '/admin/' . $area['icon'] . '" alt="">';
130
						elseif (isset($area['icon']))
131
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon'] = '<span class="generic_icons ' . $area['icon'] . '"></span>';
132
						else
133
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon'] = '<span class="generic_icons ' . $area_id . '"></span>';
134
135
						if (isset($area['icon_class']) && empty($menu_context['sections'][$section_id]['areas'][$area_id]['icon']))
136
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon_class'] = $menu_context['current_action'] . '_menu_icon ' . $area['icon_class'];
137
						elseif (isset($area['icon']))
138
						{
139
							if ((substr($area['icon'], -4) === '.png' || substr($area['icon'], -4) === '.gif') && file_exists($settings['theme_dir'] . '/images/admin/big/' . $area['icon']))
140
								$menu_context['sections'][$section_id]['areas'][$area_id]['icon_file'] = $settings['theme_url'] . '/images/admin/big/' . $area['icon'];
141
							elseif ((substr($area['icon'], -4) === '.png' || substr($area['icon'], -4) === '.gif') && file_exists($settings['default_theme_dir'] . '/images/admin/big/' . $area['icon']))
142
								$menu_context['sections'][$section_id]['areas'][$area_id]['icon_file'] = $settings['default_theme_url'] . '/images/admin/big/' . $area['icon'];
143
144
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon_class'] = $menu_context['current_action'] . '_menu_icon ' . str_replace(array('.png', '.gif'), '', $area['icon']);
145
						}
146
						else
147
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon_class'] = $menu_context['current_action'] . '_menu_icon ' . str_replace(array('.png', '.gif'), '', $area_id);
148
149
						// Some areas may be listed but not active, which we show as greyed out.
150
						$menu_context['sections'][$section_id]['areas'][$area_id]['inactive'] = !empty($area['inactive']);
151
152
						// Did it have subsections?
153
						if (!empty($area['subsections']))
154
						{
155
							$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'] = array();
156
							$first_sa = $last_sa = null;
157
							foreach ($area['subsections'] as $sa => $sub)
158
							{
159
								if ((empty($sub[1]) || allowedTo($sub[1])) && (!isset($sub['enabled']) || !empty($sub['enabled'])))
160
								{
161
									if ($first_sa == null)
162
										$first_sa = $sa;
163
164
									$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$sa] = array('label' => $sub[0]);
165
									// Custom URL?
166 View Code Duplication
									if (isset($sub['url']))
167
										$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$sa]['url'] = $sub['url'];
168
169
									// A bit complicated - but is this set?
170
									if ($menu_context['current_area'] == $area_id)
171
									{
172
										// Save which is the first...
173
										if (empty($first_sa))
174
											$first_sa = $sa;
175
176
										// Is this the current subsection?
177 View Code Duplication
										if (isset($_REQUEST['sa']) && $_REQUEST['sa'] == $sa)
178
											$menu_context['current_subsection'] = $sa;
179
										// Otherwise is it the default?
180
										elseif (!isset($menu_context['current_subsection']) && !empty($sub[2]))
181
											$menu_context['current_subsection'] = $sa;
182
									}
183
184
									// Let's assume this is the last, for now.
185
									$last_sa = $sa;
186
								}
187
								// Mark it as disabled...
188
								else
189
									$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$sa]['disabled'] = true;
190
							}
191
192
							// Set which one is first, last and selected in the group.
193
							if (!empty($menu_context['sections'][$section_id]['areas'][$area_id]['subsections']))
194
							{
195
								$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$context['right_to_left'] ? $last_sa : $first_sa]['is_first'] = true;
196
								$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$context['right_to_left'] ? $first_sa : $last_sa]['is_last'] = true;
197
198
								if ($menu_context['current_area'] == $area_id && !isset($menu_context['current_subsection']))
199
									$menu_context['current_subsection'] = $first_sa;
200
							}
201
						}
202
					}
203
				}
204
205
				// Is this the current section?
206
				if ($menu_context['current_area'] == $area_id && empty($found_section))
207
				{
208
					// Only do this once?
209
					$found_section = true;
210
211
					// Update the context if required - as we can have areas pretending to be others. ;)
212
					$menu_context['current_section'] = $section_id;
213
					$menu_context['current_area'] = isset($area['select']) ? $area['select'] : $area_id;
214
215
					// This will be the data we return.
216
					$include_data = $area;
217
				}
218
				// Make sure we have something in case it's an invalid area.
219
				elseif (empty($found_section) && empty($include_data))
220
				{
221
					$menu_context['current_section'] = $section_id;
222
					$backup_area = isset($area['select']) ? $area['select'] : $area_id;
223
					$include_data = $area;
224
				}
225
			}
226
		}
227
	}
228
229
	// Should we use a custom base url, or use the default?
230
	$menu_context['base_url'] = isset($menuOptions['base_url']) ? $menuOptions['base_url'] : $scripturl . '?action=' . $menu_context['current_action'];
231
232
	// If we didn't find the area we were looking for go to a default one.
233
	if (isset($backup_area) && empty($found_section))
234
		$menu_context['current_area'] = $backup_area;
235
236
	// If there are sections quickly goes through all the sections to check if the base menu has an url
237
	if (!empty($menu_context['current_section']))
238
	{
239
		$menu_context['sections'][$menu_context['current_section']]['selected'] = true;
240
		$menu_context['sections'][$menu_context['current_section']]['areas'][$menu_context['current_area']]['selected'] = true;
241
		if (!empty($menu_context['sections'][$menu_context['current_section']]['areas'][$menu_context['current_area']]['subsections'][$context['current_subaction']]))
242
			$menu_context['sections'][$menu_context['current_section']]['areas'][$menu_context['current_area']]['subsections'][$context['current_subaction']]['selected'] = true;
243
244
		foreach ($menu_context['sections'] as $section_id => $section)
245
			foreach ($section['areas'] as $area_id => $area)
246
			{
247
				if (!isset($menu_context['sections'][$section_id]['url']))
248
				{
249
					$menu_context['sections'][$section_id]['url'] = isset($area['url']) ? $area['url'] : $menu_context['base_url'] . ';area=' . $area_id;
250
					break;
251
				}
252
			}
253
	}
254
255
	// If still no data then return - nothing to show!
256
	if (empty($menu_context['sections']))
257
	{
258
		// Never happened!
259
		$context['max_menu_id']--;
260
		if ($context['max_menu_id'] == 0)
261
			unset($context['max_menu_id']);
262
263
		return false;
264
	}
265
266
	// Almost there - load the template and add to the template layers.
267
	loadTemplate(isset($menuOptions['template_name']) ? $menuOptions['template_name'] : 'GenericMenu');
268
	$menu_context['layer_name'] = (isset($menuOptions['layer_name']) ? $menuOptions['layer_name'] : 'generic_menu') . '_dropdown';
269
	$context['template_layers'][] = $menu_context['layer_name'];
270
271
	// Check we had something - for sanity sake.
272
	if (empty($include_data))
273
		return false;
274
275
	// Finally - return information on the selected item.
276
	$include_data += array(
277
		'current_action' => $menu_context['current_action'],
278
		'current_area' => $menu_context['current_area'],
279
		'current_section' => $menu_context['current_section'],
280
		'current_subsection' => !empty($menu_context['current_subsection']) ? $menu_context['current_subsection'] : '',
281
	);
282
283
	return $include_data;
284
}
285
286
/**
287
 * Delete a menu.
288
 * @param string $menu_id The ID of the menu to destroy or 'last' for the most recent one
289
 * @return bool|void False if the menu doesn't exist, nothing otherwise
0 ignored issues
show
Consider making the return type a bit more specific; maybe use false|null.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
290
 */
291
function destroyMenu($menu_id = 'last')
292
{
293
	global $context;
294
295
	$menu_name = $menu_id == 'last' && isset($context['max_menu_id']) && isset($context['menu_data_' . $context['max_menu_id']]) ? 'menu_data_' . $context['max_menu_id'] : 'menu_data_' . $menu_id;
296
	if (!isset($context[$menu_name]))
297
		return false;
298
299
	$layer_index = array_search($context[$menu_name]['layer_name'], $context['template_layers']);
300
	if ($layer_index !== false)
301
		unset($context['template_layers'][$layer_index]);
302
303
	unset($context[$menu_name]);
304
}
305
306
?>