1 | <?php |
||||||
2 | |||||||
3 | /** |
||||||
4 | * This file has the primary job of showing and editing people's profiles. |
||||||
5 | * It also allows the user to change some of their or another's preferences, |
||||||
6 | * and such things. |
||||||
7 | * |
||||||
8 | * Simple Machines Forum (SMF) |
||||||
9 | * |
||||||
10 | * @package SMF |
||||||
11 | * @author Simple Machines https://www.simplemachines.org |
||||||
12 | * @copyright 2022 Simple Machines and individual contributors |
||||||
13 | * @license https://www.simplemachines.org/about/smf/license.php BSD |
||||||
14 | * |
||||||
15 | * @version 2.1.0 |
||||||
16 | */ |
||||||
17 | |||||||
18 | if (!defined('SMF')) |
||||||
19 | die('No direct access...'); |
||||||
20 | |||||||
21 | /** |
||||||
22 | * The main designating function for modifying profiles. Loads up info, determins what to do, etc. |
||||||
23 | * |
||||||
24 | * @param array $post_errors Any errors that occurred |
||||||
25 | */ |
||||||
26 | function ModifyProfile($post_errors = array()) |
||||||
27 | { |
||||||
28 | global $txt, $scripturl, $user_info, $context, $sourcedir, $user_profile, $cur_profile; |
||||||
29 | global $modSettings, $memberContext, $profile_vars, $post_errors, $smcFunc; |
||||||
30 | |||||||
31 | // Don't reload this as we may have processed error strings. |
||||||
32 | if (empty($post_errors)) |
||||||
33 | loadLanguage('Profile+Drafts'); |
||||||
34 | loadTemplate('Profile'); |
||||||
35 | |||||||
36 | require_once($sourcedir . '/Subs-Menu.php'); |
||||||
37 | |||||||
38 | // Did we get the user by name... |
||||||
39 | if (isset($_REQUEST['user'])) |
||||||
40 | $memberResult = loadMemberData($_REQUEST['user'], true, 'profile'); |
||||||
41 | // ... or by id_member? |
||||||
42 | elseif (!empty($_REQUEST['u'])) |
||||||
43 | $memberResult = loadMemberData((int) $_REQUEST['u'], false, 'profile'); |
||||||
44 | // If it was just ?action=profile, edit your own profile, but only if you're not a guest. |
||||||
45 | else |
||||||
46 | { |
||||||
47 | // Members only... |
||||||
48 | is_not_guest(); |
||||||
49 | $memberResult = loadMemberData($user_info['id'], false, 'profile'); |
||||||
50 | } |
||||||
51 | |||||||
52 | // Check if loadMemberData() has returned a valid result. |
||||||
53 | if (!$memberResult) |
||||||
54 | fatal_lang_error('not_a_user', false, 404); |
||||||
55 | |||||||
56 | // If all went well, we have a valid member ID! |
||||||
57 | list ($memID) = $memberResult; |
||||||
58 | $memID = (int) $memID; |
||||||
59 | $context['id_member'] = $memID; |
||||||
60 | $cur_profile = $user_profile[$memID]; |
||||||
61 | |||||||
62 | // Let's have some information about this member ready, too. |
||||||
63 | loadMemberContext($memID); |
||||||
64 | $context['member'] = $memberContext[$memID]; |
||||||
65 | |||||||
66 | // Is this the profile of the user himself or herself? |
||||||
67 | $context['user']['is_owner'] = $memID == $user_info['id']; |
||||||
68 | |||||||
69 | // Group management isn't actually a permission. But we need it to be for this, so we need a phantom permission. |
||||||
70 | // And we care about what the current user can do, not what the user whose profile it is. |
||||||
71 | if ($user_info['mod_cache']['gq'] != '0=1') |
||||||
72 | $user_info['permissions'][] = 'approve_group_requests'; |
||||||
73 | |||||||
74 | // If paid subscriptions are enabled, make sure we actually have at least one subscription available... |
||||||
75 | $context['subs_available'] = false; |
||||||
76 | |||||||
77 | if (!empty($modSettings['paid_enabled'])) |
||||||
78 | { |
||||||
79 | $get_active_subs = $smcFunc['db_query']('', ' |
||||||
80 | SELECT COUNT(*) |
||||||
81 | FROM {db_prefix}subscriptions |
||||||
82 | WHERE active = {int:active}', array( |
||||||
83 | 'active' => 1, |
||||||
84 | ) |
||||||
85 | ); |
||||||
86 | |||||||
87 | list ($num_subs) = $smcFunc['db_fetch_row']($get_active_subs); |
||||||
88 | |||||||
89 | $context['subs_available'] = ($num_subs > 0); |
||||||
90 | |||||||
91 | $smcFunc['db_free_result']($get_active_subs); |
||||||
92 | } |
||||||
93 | |||||||
94 | /* Define all the sections within the profile area! |
||||||
95 | We start by defining the permission required - then SMF takes this and turns it into the relevant context ;) |
||||||
96 | Possible fields: |
||||||
97 | For Section: |
||||||
98 | string $title: Section title. |
||||||
99 | array $areas: Array of areas within this section. |
||||||
100 | |||||||
101 | For Areas: |
||||||
102 | string $label: Text string that will be used to show the area in the menu. |
||||||
103 | string $file: Optional text string that may contain a file name that's needed for inclusion in order to display the area properly. |
||||||
104 | string $custom_url: Optional href for area. |
||||||
105 | string $function: Function to execute for this section. Can be a call to an static method: class::method |
||||||
106 | string $class If your function is a method, set the class field with your class's name and SMF will create a new instance for it. |
||||||
107 | bool $enabled: Should area be shown? |
||||||
108 | string $sc: Session check validation to do on save - note without this save will get unset - if set. |
||||||
109 | bool $hidden: Does this not actually appear on the menu? |
||||||
110 | bool $password: Whether to require the user's password in order to save the data in the area. |
||||||
111 | array $subsections: Array of subsections, in order of appearance. |
||||||
112 | array $permission: Array of permissions to determine who can access this area. Should contain arrays $own and $any. |
||||||
113 | */ |
||||||
114 | $profile_areas = array( |
||||||
115 | 'info' => array( |
||||||
116 | 'title' => $txt['profileInfo'], |
||||||
117 | 'areas' => array( |
||||||
118 | 'summary' => array( |
||||||
119 | 'label' => $txt['summary'], |
||||||
120 | 'file' => 'Profile-View.php', |
||||||
121 | 'function' => 'summary', |
||||||
122 | 'icon' => 'administration', |
||||||
123 | 'permission' => array( |
||||||
124 | 'own' => 'is_not_guest', |
||||||
125 | 'any' => 'profile_view', |
||||||
126 | ), |
||||||
127 | ), |
||||||
128 | 'popup' => array( |
||||||
129 | 'function' => 'profile_popup', |
||||||
130 | 'permission' => array( |
||||||
131 | 'own' => 'is_not_guest', |
||||||
132 | 'any' => array(), |
||||||
133 | ), |
||||||
134 | 'select' => 'summary', |
||||||
135 | ), |
||||||
136 | 'alerts_popup' => array( |
||||||
137 | 'function' => 'alerts_popup', |
||||||
138 | 'permission' => array( |
||||||
139 | 'own' => 'is_not_guest', |
||||||
140 | 'any' => array(), |
||||||
141 | ), |
||||||
142 | 'select' => 'summary', |
||||||
143 | ), |
||||||
144 | 'statistics' => array( |
||||||
145 | 'label' => $txt['statPanel'], |
||||||
146 | 'file' => 'Profile-View.php', |
||||||
147 | 'function' => 'statPanel', |
||||||
148 | 'icon' => 'stats', |
||||||
149 | 'permission' => array( |
||||||
150 | 'own' => 'is_not_guest', |
||||||
151 | 'any' => 'profile_view', |
||||||
152 | ), |
||||||
153 | ), |
||||||
154 | 'showposts' => array( |
||||||
155 | 'label' => $txt['showPosts'], |
||||||
156 | 'file' => 'Profile-View.php', |
||||||
157 | 'function' => 'showPosts', |
||||||
158 | 'icon' => 'posts', |
||||||
159 | 'subsections' => array( |
||||||
160 | 'messages' => array($txt['showMessages'], array('is_not_guest', 'profile_view')), |
||||||
161 | 'topics' => array($txt['showTopics'], array('is_not_guest', 'profile_view')), |
||||||
162 | 'unwatchedtopics' => array($txt['showUnwatched'], array('is_not_guest', 'profile_view'), 'enabled' => $context['user']['is_owner']), |
||||||
163 | 'attach' => array($txt['showAttachments'], array('is_not_guest', 'profile_view')), |
||||||
164 | ), |
||||||
165 | 'permission' => array( |
||||||
166 | 'own' => 'is_not_guest', |
||||||
167 | 'any' => 'profile_view', |
||||||
168 | ), |
||||||
169 | ), |
||||||
170 | 'showdrafts' => array( |
||||||
171 | 'label' => $txt['drafts_show'], |
||||||
172 | 'file' => 'Drafts.php', |
||||||
173 | 'function' => 'showProfileDrafts', |
||||||
174 | 'icon' => 'drafts', |
||||||
175 | 'enabled' => !empty($modSettings['drafts_post_enabled']) && $context['user']['is_owner'], |
||||||
176 | 'permission' => array( |
||||||
177 | 'own' => 'is_not_guest', |
||||||
178 | 'any' => array(), |
||||||
179 | ), |
||||||
180 | ), |
||||||
181 | 'showalerts' => array( |
||||||
182 | 'label' => $txt['alerts_show'], |
||||||
183 | 'file' => 'Profile-View.php', |
||||||
184 | 'function' => 'showAlerts', |
||||||
185 | 'icon' => 'alerts', |
||||||
186 | 'permission' => array( |
||||||
187 | 'own' => 'is_not_guest', |
||||||
188 | 'any' => array(), |
||||||
189 | ), |
||||||
190 | ), |
||||||
191 | 'permissions' => array( |
||||||
192 | 'label' => $txt['showPermissions'], |
||||||
193 | 'file' => 'Profile-View.php', |
||||||
194 | 'function' => 'showPermissions', |
||||||
195 | 'icon' => 'permissions', |
||||||
196 | 'permission' => array( |
||||||
197 | 'own' => 'manage_permissions', |
||||||
198 | 'any' => 'manage_permissions', |
||||||
199 | ), |
||||||
200 | ), |
||||||
201 | 'tracking' => array( |
||||||
202 | 'label' => $txt['trackUser'], |
||||||
203 | 'file' => 'Profile-View.php', |
||||||
204 | 'function' => 'tracking', |
||||||
205 | 'icon' => 'logs', |
||||||
206 | 'subsections' => array( |
||||||
207 | 'activity' => array($txt['trackActivity'], 'moderate_forum'), |
||||||
208 | 'ip' => array($txt['trackIP'], 'moderate_forum'), |
||||||
209 | 'edits' => array($txt['trackEdits'], 'moderate_forum', 'enabled' => !empty($modSettings['userlog_enabled'])), |
||||||
210 | 'groupreq' => array($txt['trackGroupRequests'], 'approve_group_requests', 'enabled' => !empty($modSettings['show_group_membership'])), |
||||||
211 | 'logins' => array($txt['trackLogins'], 'moderate_forum', 'enabled' => !empty($modSettings['loginHistoryDays'])), |
||||||
212 | ), |
||||||
213 | 'permission' => array( |
||||||
214 | 'own' => array('moderate_forum', 'approve_group_requests'), |
||||||
215 | 'any' => array('moderate_forum', 'approve_group_requests'), |
||||||
216 | ), |
||||||
217 | ), |
||||||
218 | 'viewwarning' => array( |
||||||
219 | 'label' => $txt['profile_view_warnings'], |
||||||
220 | 'enabled' => $modSettings['warning_settings'][0] == 1 && $cur_profile['warning'], |
||||||
221 | 'file' => 'Profile-View.php', |
||||||
222 | 'function' => 'viewWarning', |
||||||
223 | 'icon' => 'warning', |
||||||
224 | 'permission' => array( |
||||||
225 | 'own' => array('view_warning_own', 'view_warning_any', 'issue_warning', 'moderate_forum'), |
||||||
226 | 'any' => array('view_warning_any', 'issue_warning', 'moderate_forum'), |
||||||
227 | ), |
||||||
228 | ), |
||||||
229 | ), |
||||||
230 | ), |
||||||
231 | 'edit_profile' => array( |
||||||
232 | 'title' => $txt['forumprofile'], |
||||||
233 | 'areas' => array( |
||||||
234 | 'account' => array( |
||||||
235 | 'label' => $txt['account'], |
||||||
236 | 'file' => 'Profile-Modify.php', |
||||||
237 | 'function' => 'account', |
||||||
238 | 'icon' => 'maintain', |
||||||
239 | 'enabled' => $context['user']['is_admin'] || ($cur_profile['id_group'] != 1 && !in_array(1, explode(',', $cur_profile['additional_groups']))), |
||||||
240 | 'sc' => 'post', |
||||||
241 | 'token' => 'profile-ac%u', |
||||||
242 | 'password' => true, |
||||||
243 | 'permission' => array( |
||||||
244 | 'own' => array('profile_identity_any', 'profile_identity_own', 'profile_password_any', 'profile_password_own', 'manage_membergroups'), |
||||||
245 | 'any' => array('profile_identity_any', 'profile_password_any', 'manage_membergroups'), |
||||||
246 | ), |
||||||
247 | ), |
||||||
248 | 'tfasetup' => array( |
||||||
249 | 'label' => $txt['account'], |
||||||
250 | 'file' => 'Profile-Modify.php', |
||||||
251 | 'function' => 'tfasetup', |
||||||
252 | 'token' => 'profile-tfa%u', |
||||||
253 | 'enabled' => !empty($modSettings['tfa_mode']), |
||||||
254 | 'hidden' => true, |
||||||
255 | 'select' => 'account', |
||||||
256 | 'permission' => array( |
||||||
257 | 'own' => array('profile_password_own'), |
||||||
258 | 'any' => array('profile_password_any'), |
||||||
259 | ), |
||||||
260 | ), |
||||||
261 | 'tfadisable' => array( |
||||||
262 | 'label' => $txt['account'], |
||||||
263 | 'file' => 'Profile-Modify.php', |
||||||
264 | 'function' => 'tfadisable', |
||||||
265 | 'token' => 'profile-tfa%u', |
||||||
266 | 'sc' => 'post', |
||||||
267 | 'password' => true, |
||||||
268 | 'enabled' => !empty($modSettings['tfa_mode']), |
||||||
269 | 'hidden' => true, |
||||||
270 | 'select' => 'account', |
||||||
271 | 'permission' => array( |
||||||
272 | 'own' => array('profile_password_own'), |
||||||
273 | 'any' => array('profile_password_any'), |
||||||
274 | ), |
||||||
275 | ), |
||||||
276 | 'forumprofile' => array( |
||||||
277 | 'label' => $txt['forumprofile'], |
||||||
278 | 'file' => 'Profile-Modify.php', |
||||||
279 | 'function' => 'forumProfile', |
||||||
280 | 'icon' => 'members', |
||||||
281 | 'sc' => 'post', |
||||||
282 | 'token' => 'profile-fp%u', |
||||||
283 | 'permission' => array( |
||||||
284 | 'own' => array('profile_forum_any', 'profile_forum_own'), |
||||||
285 | 'any' => array('profile_forum_any'), |
||||||
286 | ), |
||||||
287 | ), |
||||||
288 | 'theme' => array( |
||||||
289 | 'label' => $txt['theme'], |
||||||
290 | 'file' => 'Profile-Modify.php', |
||||||
291 | 'function' => 'theme', |
||||||
292 | 'icon' => 'features', |
||||||
293 | 'sc' => 'post', |
||||||
294 | 'token' => 'profile-th%u', |
||||||
295 | 'permission' => array( |
||||||
296 | 'own' => array('profile_extra_any', 'profile_extra_own'), |
||||||
297 | 'any' => array('profile_extra_any'), |
||||||
298 | ), |
||||||
299 | ), |
||||||
300 | 'notification' => array( |
||||||
301 | 'label' => $txt['notification'], |
||||||
302 | 'file' => 'Profile-Modify.php', |
||||||
303 | 'function' => 'notification', |
||||||
304 | 'icon' => 'alerts', |
||||||
305 | 'sc' => 'post', |
||||||
306 | //'token' => 'profile-nt%u', This is not checked here. We do it in the function itself - but if it was checked, this is what it'd be. |
||||||
307 | 'subsections' => array( |
||||||
308 | 'alerts' => array($txt['alert_prefs'], array('is_not_guest', 'profile_extra_any')), |
||||||
309 | 'topics' => array($txt['watched_topics'], array('is_not_guest', 'profile_extra_any')), |
||||||
310 | 'boards' => array($txt['watched_boards'], array('is_not_guest', 'profile_extra_any')), |
||||||
311 | ), |
||||||
312 | 'permission' => array( |
||||||
313 | 'own' => array('is_not_guest'), |
||||||
314 | 'any' => array('profile_extra_any'), // If you change this, update it in the functions themselves; we delegate all saving checks there. |
||||||
315 | ), |
||||||
316 | ), |
||||||
317 | 'ignoreboards' => array( |
||||||
318 | 'label' => $txt['ignoreboards'], |
||||||
319 | 'file' => 'Profile-Modify.php', |
||||||
320 | 'function' => 'ignoreboards', |
||||||
321 | 'icon' => 'boards', |
||||||
322 | 'enabled' => !empty($modSettings['allow_ignore_boards']), |
||||||
323 | 'sc' => 'post', |
||||||
324 | 'token' => 'profile-ib%u', |
||||||
325 | 'permission' => array( |
||||||
326 | 'own' => array('profile_extra_any', 'profile_extra_own'), |
||||||
327 | 'any' => array('profile_extra_any'), |
||||||
328 | ), |
||||||
329 | ), |
||||||
330 | 'lists' => array( |
||||||
331 | 'label' => $txt['editBuddyIgnoreLists'], |
||||||
332 | 'file' => 'Profile-Modify.php', |
||||||
333 | 'function' => 'editBuddyIgnoreLists', |
||||||
334 | 'icon' => 'frenemy', |
||||||
335 | 'enabled' => !empty($modSettings['enable_buddylist']) && $context['user']['is_owner'], |
||||||
336 | 'sc' => 'post', |
||||||
337 | 'subsections' => array( |
||||||
338 | 'buddies' => array($txt['editBuddies']), |
||||||
339 | 'ignore' => array($txt['editIgnoreList']), |
||||||
340 | ), |
||||||
341 | 'permission' => array( |
||||||
342 | 'own' => array('profile_extra_any', 'profile_extra_own'), |
||||||
343 | 'any' => array(), |
||||||
344 | ), |
||||||
345 | ), |
||||||
346 | 'groupmembership' => array( |
||||||
347 | 'label' => $txt['groupmembership'], |
||||||
348 | 'file' => 'Profile-Modify.php', |
||||||
349 | 'function' => 'groupMembership', |
||||||
350 | 'icon' => 'people', |
||||||
351 | 'enabled' => !empty($modSettings['show_group_membership']) && $context['user']['is_owner'], |
||||||
352 | 'sc' => 'request', |
||||||
353 | 'token' => 'profile-gm%u', |
||||||
354 | 'token_type' => 'request', |
||||||
355 | 'permission' => array( |
||||||
356 | 'own' => array('is_not_guest'), |
||||||
357 | 'any' => array('manage_membergroups'), |
||||||
358 | ), |
||||||
359 | ), |
||||||
360 | ), |
||||||
361 | ), |
||||||
362 | 'profile_action' => array( |
||||||
363 | 'title' => $txt['profileAction'], |
||||||
364 | 'areas' => array( |
||||||
365 | 'sendpm' => array( |
||||||
366 | 'label' => $txt['profileSendIm'], |
||||||
367 | 'custom_url' => $scripturl . '?action=pm;sa=send', |
||||||
368 | 'icon' => 'personal_message', |
||||||
369 | 'enabled' => allowedTo('profile_view'), |
||||||
370 | 'permission' => array( |
||||||
371 | 'own' => array(), |
||||||
372 | 'any' => array('pm_send'), |
||||||
373 | ), |
||||||
374 | ), |
||||||
375 | 'report' => array( |
||||||
376 | 'label' => $txt['report_profile'], |
||||||
377 | 'custom_url' => $scripturl . '?action=reporttm;' . $context['session_var'] . '=' . $context['session_id'], |
||||||
378 | 'icon' => 'warning', |
||||||
379 | 'enabled' => allowedTo('profile_view'), |
||||||
380 | 'permission' => array( |
||||||
381 | 'own' => array(), |
||||||
382 | 'any' => array('report_user'), |
||||||
383 | ), |
||||||
384 | ), |
||||||
385 | 'issuewarning' => array( |
||||||
386 | 'label' => $txt['profile_issue_warning'], |
||||||
387 | 'enabled' => $modSettings['warning_settings'][0] == 1, |
||||||
388 | 'file' => 'Profile-Actions.php', |
||||||
389 | 'function' => 'issueWarning', |
||||||
390 | 'icon' => 'warning', |
||||||
391 | 'token' => 'profile-iw%u', |
||||||
392 | 'permission' => array( |
||||||
393 | 'own' => array(), |
||||||
394 | 'any' => array('issue_warning'), |
||||||
395 | ), |
||||||
396 | ), |
||||||
397 | 'banuser' => array( |
||||||
398 | 'label' => $txt['profileBanUser'], |
||||||
399 | 'custom_url' => $scripturl . '?action=admin;area=ban;sa=add', |
||||||
400 | 'icon' => 'ban', |
||||||
401 | 'enabled' => $cur_profile['id_group'] != 1 && !in_array(1, explode(',', $cur_profile['additional_groups'])), |
||||||
402 | 'permission' => array( |
||||||
403 | 'own' => array(), |
||||||
404 | 'any' => array('manage_bans'), |
||||||
405 | ), |
||||||
406 | ), |
||||||
407 | 'subscriptions' => array( |
||||||
408 | 'label' => $txt['subscriptions'], |
||||||
409 | 'file' => 'Profile-Actions.php', |
||||||
410 | 'function' => 'subscriptions', |
||||||
411 | 'icon' => 'paid', |
||||||
412 | 'enabled' => !empty($modSettings['paid_enabled']) && $context['subs_available'], |
||||||
413 | 'permission' => array( |
||||||
414 | 'own' => array('is_not_guest'), |
||||||
415 | 'any' => array('moderate_forum'), |
||||||
416 | ), |
||||||
417 | ), |
||||||
418 | 'getprofiledata' => array( |
||||||
419 | 'label' => $txt['export_profile_data'], |
||||||
420 | 'file' => 'Profile-Export.php', |
||||||
421 | 'function' => 'export_profile_data', |
||||||
422 | 'icon' => 'packages', |
||||||
423 | // 'token' => 'profile-ex%u', // This is not checked here. We do it in the function itself - but if it was checked, this is what it'd be. |
||||||
424 | 'permission' => array( |
||||||
425 | 'own' => array('profile_view_own'), |
||||||
426 | 'any' => array('moderate_forum'), |
||||||
427 | ), |
||||||
428 | ), |
||||||
429 | 'download' => array( |
||||||
430 | 'label' => $txt['export_profile_data'], |
||||||
431 | 'file' => 'Profile-Export.php', |
||||||
432 | 'function' => 'download_export_file', |
||||||
433 | 'icon' => 'packages', |
||||||
434 | 'hidden' => true, |
||||||
435 | 'select' => 'getprofiledata', |
||||||
436 | 'permission' => array( |
||||||
437 | 'own' => array('profile_view_own'), |
||||||
438 | 'any' => array('moderate_forum'), |
||||||
439 | ), |
||||||
440 | ), |
||||||
441 | 'dlattach' => array( |
||||||
442 | 'label' => $txt['export_profile_data'], |
||||||
443 | 'file' => 'Profile-Export.php', |
||||||
444 | 'function' => 'export_attachment', |
||||||
445 | 'icon' => 'packages', |
||||||
446 | 'hidden' => true, |
||||||
447 | 'select' => 'getprofiledata', |
||||||
448 | 'permission' => array( |
||||||
449 | 'own' => array('profile_view_own'), |
||||||
450 | 'any' => array(), |
||||||
451 | ), |
||||||
452 | ), |
||||||
453 | 'deleteaccount' => array( |
||||||
454 | 'label' => $txt['deleteAccount'], |
||||||
455 | 'file' => 'Profile-Actions.php', |
||||||
456 | 'function' => 'deleteAccount', |
||||||
457 | 'icon' => 'members_delete', |
||||||
458 | 'sc' => 'post', |
||||||
459 | 'token' => 'profile-da%u', |
||||||
460 | 'password' => true, |
||||||
461 | 'permission' => array( |
||||||
462 | 'own' => array('profile_remove_any', 'profile_remove_own'), |
||||||
463 | 'any' => array('profile_remove_any'), |
||||||
464 | ), |
||||||
465 | ), |
||||||
466 | 'activateaccount' => array( |
||||||
467 | 'file' => 'Profile-Actions.php', |
||||||
468 | 'function' => 'activateAccount', |
||||||
469 | 'icon' => 'regcenter', |
||||||
470 | 'sc' => 'get', |
||||||
471 | 'token' => 'profile-aa%u', |
||||||
472 | 'token_type' => 'get', |
||||||
473 | 'permission' => array( |
||||||
474 | 'own' => array(), |
||||||
475 | 'any' => array('moderate_forum'), |
||||||
476 | ), |
||||||
477 | ), |
||||||
478 | // A logout link just for the popup menu. |
||||||
479 | 'logout' => array( |
||||||
480 | 'label' => $txt['logout'], |
||||||
481 | 'custom_url' => $scripturl . '?action=logout;%1$s=%2$s', |
||||||
482 | 'icon' => 'logout', |
||||||
483 | 'enabled' => !empty($_REQUEST['area']) && $_REQUEST['area'] === 'popup', |
||||||
484 | 'permission' => array( |
||||||
485 | 'own' => array('is_not_guest'), |
||||||
486 | 'any' => array(), |
||||||
487 | ), |
||||||
488 | ), |
||||||
489 | ), |
||||||
490 | ), |
||||||
491 | ); |
||||||
492 | |||||||
493 | // Let them modify profile areas easily. |
||||||
494 | call_integration_hook('integrate_pre_profile_areas', array(&$profile_areas)); |
||||||
495 | |||||||
496 | // Do some cleaning ready for the menu function. |
||||||
497 | $context['password_areas'] = array(); |
||||||
498 | $current_area = isset($_REQUEST['area']) ? $_REQUEST['area'] : ''; |
||||||
499 | |||||||
500 | foreach ($profile_areas as $section_id => $section) |
||||||
501 | { |
||||||
502 | // Do a bit of spring cleaning so to speak. |
||||||
503 | foreach ($section['areas'] as $area_id => $area) |
||||||
504 | { |
||||||
505 | // If it said no permissions that meant it wasn't valid! |
||||||
506 | if (empty($area['permission'][$context['user']['is_owner'] ? 'own' : 'any'])) |
||||||
507 | $profile_areas[$section_id]['areas'][$area_id]['enabled'] = false; |
||||||
508 | // Otherwise pick the right set. |
||||||
509 | else |
||||||
510 | $profile_areas[$section_id]['areas'][$area_id]['permission'] = $area['permission'][$context['user']['is_owner'] ? 'own' : 'any']; |
||||||
511 | |||||||
512 | // Password required in most cases |
||||||
513 | if (!empty($area['password'])) |
||||||
514 | $context['password_areas'][] = $area_id; |
||||||
515 | } |
||||||
516 | } |
||||||
517 | |||||||
518 | // Is there an updated message to show? |
||||||
519 | if (isset($_GET['updated'])) |
||||||
520 | $context['profile_updated'] = $txt['profile_updated_own']; |
||||||
521 | |||||||
522 | // Set a few options for the menu. |
||||||
523 | $menuOptions = array( |
||||||
524 | 'disable_url_session_check' => true, |
||||||
525 | 'current_area' => $current_area, |
||||||
526 | 'extra_url_parameters' => array( |
||||||
527 | 'u' => $context['id_member'], |
||||||
528 | ), |
||||||
529 | ); |
||||||
530 | |||||||
531 | // Logging out requires the session id in the url. |
||||||
532 | $profile_areas['profile_action']['areas']['logout']['custom_url'] = sprintf($profile_areas['profile_action']['areas']['logout']['custom_url'], $context['session_var'], $context['session_id']); |
||||||
533 | |||||||
534 | // Actually create the menu! |
||||||
535 | $profile_include_data = createMenu($profile_areas, $menuOptions); |
||||||
536 | |||||||
537 | // No menu means no access. |
||||||
538 | if (!$profile_include_data && (!$user_info['is_guest'] || validateSession())) |
||||||
539 | fatal_lang_error('no_access', false); |
||||||
540 | |||||||
541 | // Make a note of the Unique ID for this menu. |
||||||
542 | $context['profile_menu_id'] = $context['max_menu_id']; |
||||||
543 | $context['profile_menu_name'] = 'menu_data_' . $context['profile_menu_id']; |
||||||
544 | |||||||
545 | // Set the selected item - now it's been validated. |
||||||
546 | $current_area = $profile_include_data['current_area']; |
||||||
547 | $current_sa = $profile_include_data['current_subsection']; |
||||||
548 | $context['menu_item_selected'] = $current_area; |
||||||
549 | |||||||
550 | // Before we go any further, let's work on the area we've said is valid. Note this is done here just in case we ever compromise the menu function in error! |
||||||
551 | $context['completed_save'] = false; |
||||||
552 | $context['do_preview'] = isset($_REQUEST['preview_signature']); |
||||||
553 | |||||||
554 | $security_checks = array(); |
||||||
555 | $found_area = false; |
||||||
556 | foreach ($profile_areas as $section_id => $section) |
||||||
557 | { |
||||||
558 | // Do a bit of spring cleaning so to speak. |
||||||
559 | foreach ($section['areas'] as $area_id => $area) |
||||||
560 | { |
||||||
561 | // Is this our area? |
||||||
562 | if ($current_area == $area_id) |
||||||
563 | { |
||||||
564 | // This can't happen - but is a security check. |
||||||
565 | if ((isset($section['enabled']) && $section['enabled'] == false) || (isset($area['enabled']) && $area['enabled'] == false)) |
||||||
566 | fatal_lang_error('no_access', false); |
||||||
567 | |||||||
568 | // Are we saving data in a valid area? |
||||||
569 | if (isset($area['sc']) && (isset($_REQUEST['save']) || $context['do_preview'])) |
||||||
570 | { |
||||||
571 | $security_checks['session'] = $area['sc']; |
||||||
572 | $context['completed_save'] = true; |
||||||
573 | } |
||||||
574 | |||||||
575 | // Do we need to perform a token check? |
||||||
576 | if (!empty($area['token'])) |
||||||
577 | { |
||||||
578 | $security_checks[isset($_REQUEST['save']) ? 'validateToken' : 'needsToken'] = $area['token']; |
||||||
579 | $token_name = $area['token'] !== true ? str_replace('%u', $context['id_member'], $area['token']) : 'profile-u' . $context['id_member']; |
||||||
580 | |||||||
581 | $token_type = isset($area['token_type']) && in_array($area['token_type'], array('request', 'post', 'get')) ? $area['token_type'] : 'post'; |
||||||
582 | } |
||||||
583 | |||||||
584 | // Does this require session validating? |
||||||
585 | if (!empty($area['validate']) || (isset($_REQUEST['save']) && !$context['user']['is_owner'] && ($area_id != 'issuewarning' || empty($modSettings['securityDisable_moderate'])))) |
||||||
586 | $security_checks['validate'] = true; |
||||||
587 | |||||||
588 | // Permissions for good measure. |
||||||
589 | if (!empty($profile_include_data['permission'])) |
||||||
590 | $security_checks['permission'] = $profile_include_data['permission']; |
||||||
591 | |||||||
592 | // Either way got something. |
||||||
593 | $found_area = true; |
||||||
594 | } |
||||||
595 | } |
||||||
596 | } |
||||||
597 | |||||||
598 | // Oh dear, some serious security lapse is going on here... we'll put a stop to that! |
||||||
599 | if (!$found_area) |
||||||
600 | fatal_lang_error('no_access', false); |
||||||
601 | |||||||
602 | // Release this now. |
||||||
603 | unset($profile_areas); |
||||||
604 | |||||||
605 | // Now the context is setup have we got any security checks to carry out additional to that above? |
||||||
606 | if (isset($security_checks['session'])) |
||||||
607 | checkSession($security_checks['session']); |
||||||
608 | if (isset($security_checks['validate'])) |
||||||
609 | validateSession(); |
||||||
610 | if (isset($security_checks['validateToken'])) |
||||||
611 | validateToken($token_name, $token_type); |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
![]() Comprehensibility
Best Practice
introduced
by
|
|||||||
612 | if (isset($security_checks['permission'])) |
||||||
613 | isAllowedTo($security_checks['permission']); |
||||||
614 | |||||||
615 | // Create a token if needed. |
||||||
616 | if (isset($security_checks['needsToken']) || isset($security_checks['validateToken'])) |
||||||
617 | { |
||||||
618 | createToken($token_name, $token_type); |
||||||
619 | $context['token_check'] = $token_name; |
||||||
620 | } |
||||||
621 | |||||||
622 | // File to include? |
||||||
623 | if (isset($profile_include_data['file'])) |
||||||
624 | require_once($sourcedir . '/' . $profile_include_data['file']); |
||||||
625 | |||||||
626 | // Build the link tree. |
||||||
627 | $context['linktree'][] = array( |
||||||
628 | 'url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : ''), |
||||||
629 | 'name' => sprintf($txt['profile_of_username'], $context['member']['name']), |
||||||
630 | ); |
||||||
631 | |||||||
632 | if (!empty($profile_include_data['label'])) |
||||||
633 | $context['linktree'][] = array( |
||||||
634 | 'url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : '') . ';area=' . $profile_include_data['current_area'], |
||||||
635 | 'name' => $profile_include_data['label'], |
||||||
636 | ); |
||||||
637 | |||||||
638 | if (!empty($profile_include_data['current_subsection']) && $profile_include_data['subsections'][$profile_include_data['current_subsection']][0] != $profile_include_data['label']) |
||||||
639 | $context['linktree'][] = array( |
||||||
640 | 'url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : '') . ';area=' . $profile_include_data['current_area'] . ';sa=' . $profile_include_data['current_subsection'], |
||||||
641 | 'name' => $profile_include_data['subsections'][$profile_include_data['current_subsection']][0], |
||||||
642 | ); |
||||||
643 | |||||||
644 | // Set the template for this area and add the profile layer. |
||||||
645 | $context['sub_template'] = $profile_include_data['function']; |
||||||
646 | $context['template_layers'][] = 'profile'; |
||||||
647 | |||||||
648 | // All the subactions that require a user password in order to validate. |
||||||
649 | $check_password = $context['user']['is_owner'] && in_array($profile_include_data['current_area'], $context['password_areas']); |
||||||
650 | $context['require_password'] = $check_password; |
||||||
651 | |||||||
652 | loadJavaScriptFile('profile.js', array('defer' => false, 'minimize' => true), 'smf_profile'); |
||||||
653 | |||||||
654 | // These will get populated soon! |
||||||
655 | $post_errors = array(); |
||||||
656 | $profile_vars = array(); |
||||||
657 | |||||||
658 | // Right - are we saving - if so let's save the old data first. |
||||||
659 | if ($context['completed_save']) |
||||||
660 | { |
||||||
661 | // Clean up the POST variables. |
||||||
662 | $_POST = htmltrim__recursive($_POST); |
||||||
663 | $_POST = htmlspecialchars__recursive($_POST); |
||||||
664 | |||||||
665 | if ($check_password) |
||||||
666 | { |
||||||
667 | // Check to ensure we're forcing SSL for authentication |
||||||
668 | if (!empty($modSettings['force_ssl']) && empty($maintenance) && !httpsOn()) |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
669 | fatal_lang_error('login_ssl_required', false); |
||||||
670 | |||||||
671 | $password = isset($_POST['oldpasswrd']) ? $_POST['oldpasswrd'] : ''; |
||||||
672 | |||||||
673 | // You didn't even enter a password! |
||||||
674 | if (trim($password) == '') |
||||||
675 | $post_errors[] = 'no_password'; |
||||||
676 | |||||||
677 | // Since the password got modified due to all the $_POST cleaning, lets undo it so we can get the correct password |
||||||
678 | $password = un_htmlspecialchars($password); |
||||||
679 | |||||||
680 | // Does the integration want to check passwords? |
||||||
681 | $good_password = in_array(true, call_integration_hook('integrate_verify_password', array($cur_profile['member_name'], $password, false)), true); |
||||||
682 | |||||||
683 | // Bad password!!! |
||||||
684 | if (!$good_password && !hash_verify_password($user_profile[$memID]['member_name'], $password, $user_info['passwd'])) |
||||||
685 | $post_errors[] = 'bad_password'; |
||||||
686 | |||||||
687 | // Warn other elements not to jump the gun and do custom changes! |
||||||
688 | if (in_array('bad_password', $post_errors)) |
||||||
689 | $context['password_auth_failed'] = true; |
||||||
690 | } |
||||||
691 | |||||||
692 | // Change the IP address in the database. |
||||||
693 | if ($context['user']['is_owner'] && $menuOptions['current_area'] != 'tfasetup') |
||||||
694 | $profile_vars['member_ip'] = $user_info['ip']; |
||||||
695 | |||||||
696 | // Now call the sub-action function... |
||||||
697 | if ($current_area == 'activateaccount') |
||||||
698 | { |
||||||
699 | if (empty($post_errors)) |
||||||
700 | activateAccount($memID); |
||||||
701 | } |
||||||
702 | elseif ($current_area == 'deleteaccount') |
||||||
703 | { |
||||||
704 | if (empty($post_errors)) |
||||||
705 | { |
||||||
706 | deleteAccount2($memID); |
||||||
707 | redirectexit(); |
||||||
708 | } |
||||||
709 | } |
||||||
710 | elseif ($menuOptions['current_area'] == 'tfadisable') |
||||||
711 | { |
||||||
712 | // Already checked the password, token, permissions, and session. |
||||||
713 | $profile_vars += array( |
||||||
714 | 'tfa_secret' => '', |
||||||
715 | 'tfa_backup' => '', |
||||||
716 | ); |
||||||
717 | } |
||||||
718 | elseif ($current_area == 'groupmembership' && empty($post_errors)) |
||||||
719 | { |
||||||
720 | $msg = groupMembership2($profile_vars, $post_errors, $memID); |
||||||
721 | |||||||
722 | // Whatever we've done, we have nothing else to do here... |
||||||
723 | redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $memID) . ';area=groupmembership' . (!empty($msg) ? ';msg=' . $msg : '')); |
||||||
724 | } |
||||||
725 | elseif (in_array($current_area, array('account', 'forumprofile', 'theme'))) |
||||||
726 | saveProfileFields(); |
||||||
727 | else |
||||||
728 | { |
||||||
729 | $force_redirect = true; |
||||||
730 | // Ensure we include this. |
||||||
731 | require_once($sourcedir . '/Profile-Modify.php'); |
||||||
732 | saveProfileChanges($profile_vars, $post_errors, $memID); |
||||||
733 | } |
||||||
734 | |||||||
735 | call_integration_hook('integrate_profile_save', array(&$profile_vars, &$post_errors, $memID, $cur_profile, $current_area)); |
||||||
736 | |||||||
737 | // There was a problem, let them try to re-enter. |
||||||
738 | if (!empty($post_errors)) |
||||||
739 | { |
||||||
740 | // Load the language file so we can give a nice explanation of the errors. |
||||||
741 | loadLanguage('Errors'); |
||||||
742 | $context['post_errors'] = $post_errors; |
||||||
743 | } |
||||||
744 | elseif (!empty($profile_vars)) |
||||||
745 | { |
||||||
746 | // If we've changed the password, notify any integration that may be listening in. |
||||||
747 | if (isset($profile_vars['passwd'])) |
||||||
748 | call_integration_hook('integrate_reset_pass', array($cur_profile['member_name'], $cur_profile['member_name'], $_POST['passwrd2'])); |
||||||
749 | |||||||
750 | updateMemberData($memID, $profile_vars); |
||||||
751 | |||||||
752 | // What if this is the newest member? |
||||||
753 | if ($modSettings['latestMember'] == $memID) |
||||||
754 | updateStats('member'); |
||||||
755 | elseif (isset($profile_vars['real_name'])) |
||||||
756 | updateSettings(array('memberlist_updated' => time())); |
||||||
757 | |||||||
758 | // If the member changed his/her birthdate, update calendar statistics. |
||||||
759 | if (isset($profile_vars['birthdate']) || isset($profile_vars['real_name'])) |
||||||
760 | updateSettings(array( |
||||||
761 | 'calendar_updated' => time(), |
||||||
762 | )); |
||||||
763 | |||||||
764 | // Anything worth logging? |
||||||
765 | if (!empty($context['log_changes']) && !empty($modSettings['modlog_enabled'])) |
||||||
766 | { |
||||||
767 | $log_changes = array(); |
||||||
768 | require_once($sourcedir . '/Logging.php'); |
||||||
769 | foreach ($context['log_changes'] as $k => $v) |
||||||
770 | $log_changes[] = array( |
||||||
771 | 'action' => $k, |
||||||
772 | 'log_type' => 'user', |
||||||
773 | 'extra' => array_merge($v, array( |
||||||
774 | 'applicator' => $user_info['id'], |
||||||
775 | 'member_affected' => $memID, |
||||||
776 | )), |
||||||
777 | ); |
||||||
778 | |||||||
779 | logActions($log_changes); |
||||||
780 | } |
||||||
781 | |||||||
782 | // Have we got any post save functions to execute? |
||||||
783 | if (!empty($context['profile_execute_on_save'])) |
||||||
784 | foreach ($context['profile_execute_on_save'] as $saveFunc) |
||||||
785 | $saveFunc(); |
||||||
786 | |||||||
787 | // Let them know it worked! |
||||||
788 | $context['profile_updated'] = $context['user']['is_owner'] ? $txt['profile_updated_own'] : sprintf($txt['profile_updated_else'], $cur_profile['member_name']); |
||||||
789 | |||||||
790 | // Invalidate any cached data. |
||||||
791 | cache_put_data('member_data-profile-' . $memID, null, 0); |
||||||
792 | } |
||||||
793 | } |
||||||
794 | |||||||
795 | // Have some errors for some reason? |
||||||
796 | if (!empty($post_errors)) |
||||||
797 | { |
||||||
798 | // Set all the errors so the template knows what went wrong. |
||||||
799 | foreach ($post_errors as $error_type) |
||||||
800 | $context['modify_error'][$error_type] = true; |
||||||
801 | } |
||||||
802 | // If it's you then we should redirect upon save. |
||||||
803 | elseif (!empty($profile_vars) && $context['user']['is_owner'] && !$context['do_preview']) |
||||||
804 | redirectexit('action=profile;area=' . $current_area . (!empty($current_sa) ? ';sa=' . $current_sa : '') . ';updated'); |
||||||
805 | elseif (!empty($force_redirect)) |
||||||
806 | redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $memID) . ';area=' . $current_area); |
||||||
807 | |||||||
808 | // Get the right callable. |
||||||
809 | $call = call_helper($profile_include_data['function'], true); |
||||||
810 | |||||||
811 | // Is it valid? |
||||||
812 | if (!empty($call)) |
||||||
813 | call_user_func($call, $memID); |
||||||
814 | |||||||
815 | // Set the page title if it's not already set... |
||||||
816 | if (!isset($context['page_title'])) |
||||||
817 | $context['page_title'] = $txt['profile'] . (isset($txt[$current_area]) ? ' - ' . $txt[$current_area] : ''); |
||||||
818 | } |
||||||
819 | |||||||
820 | /** |
||||||
821 | * Set up the requirements for the profile popup - the area that is shown as the popup menu for the current user. |
||||||
822 | * |
||||||
823 | * @param int $memID The ID of the member |
||||||
824 | */ |
||||||
825 | function profile_popup($memID) |
||||||
826 | { |
||||||
827 | global $context, $scripturl, $txt, $db_show_debug; |
||||||
828 | |||||||
829 | // We do not want to output debug information here. |
||||||
830 | $db_show_debug = false; |
||||||
831 | |||||||
832 | // We only want to output our little layer here. |
||||||
833 | $context['template_layers'] = array(); |
||||||
834 | |||||||
835 | // This list will pull from the master list wherever possible. Hopefully it should be clear what does what. |
||||||
836 | $profile_items = array( |
||||||
837 | array( |
||||||
838 | 'menu' => 'edit_profile', |
||||||
839 | 'area' => 'account', |
||||||
840 | ), |
||||||
841 | array( |
||||||
842 | 'menu' => 'edit_profile', |
||||||
843 | 'area' => 'forumprofile', |
||||||
844 | 'title' => $txt['popup_forumprofile'], |
||||||
845 | ), |
||||||
846 | array( |
||||||
847 | 'menu' => 'edit_profile', |
||||||
848 | 'area' => 'theme', |
||||||
849 | 'title' => $txt['theme'], |
||||||
850 | ), |
||||||
851 | array( |
||||||
852 | 'menu' => 'edit_profile', |
||||||
853 | 'area' => 'notification', |
||||||
854 | ), |
||||||
855 | array( |
||||||
856 | 'menu' => 'edit_profile', |
||||||
857 | 'area' => 'ignoreboards', |
||||||
858 | ), |
||||||
859 | array( |
||||||
860 | 'menu' => 'edit_profile', |
||||||
861 | 'area' => 'lists', |
||||||
862 | 'url' => $scripturl . '?action=profile;area=lists;sa=ignore', |
||||||
863 | 'title' => $txt['popup_ignore'], |
||||||
864 | ), |
||||||
865 | array( |
||||||
866 | 'menu' => 'info', |
||||||
867 | 'area' => 'showposts', |
||||||
868 | 'title' => $txt['popup_showposts'], |
||||||
869 | ), |
||||||
870 | array( |
||||||
871 | 'menu' => 'info', |
||||||
872 | 'area' => 'showdrafts', |
||||||
873 | 'title' => $txt['popup_showdrafts'], |
||||||
874 | ), |
||||||
875 | array( |
||||||
876 | 'menu' => 'edit_profile', |
||||||
877 | 'area' => 'groupmembership', |
||||||
878 | 'title' => $txt['popup_groupmembership'], |
||||||
879 | ), |
||||||
880 | array( |
||||||
881 | 'menu' => 'profile_action', |
||||||
882 | 'area' => 'subscriptions', |
||||||
883 | 'title' => $txt['popup_subscriptions'], |
||||||
884 | ), |
||||||
885 | array( |
||||||
886 | 'menu' => 'profile_action', |
||||||
887 | 'area' => 'logout', |
||||||
888 | ), |
||||||
889 | ); |
||||||
890 | |||||||
891 | call_integration_hook('integrate_profile_popup', array(&$profile_items)); |
||||||
892 | |||||||
893 | // Now check if these items are available |
||||||
894 | $context['profile_items'] = array(); |
||||||
895 | $menu_context = &$context[$context['profile_menu_name']]['sections']; |
||||||
896 | foreach ($profile_items as $item) |
||||||
897 | { |
||||||
898 | if (isset($menu_context[$item['menu']]['areas'][$item['area']])) |
||||||
899 | { |
||||||
900 | $context['profile_items'][] = $item; |
||||||
901 | } |
||||||
902 | } |
||||||
903 | } |
||||||
904 | |||||||
905 | /** |
||||||
906 | * Set up the requirements for the alerts popup - the area that shows all the alerts just quickly for the current user. |
||||||
907 | * |
||||||
908 | * @param int $memID The ID of the member |
||||||
909 | */ |
||||||
910 | function alerts_popup($memID) |
||||||
911 | { |
||||||
912 | global $context, $sourcedir, $db_show_debug, $cur_profile, $modSettings; |
||||||
913 | |||||||
914 | // Load the Alerts language file. |
||||||
915 | loadLanguage('Alerts'); |
||||||
916 | |||||||
917 | // We do not want to output debug information here. |
||||||
918 | $db_show_debug = false; |
||||||
919 | |||||||
920 | // We only want to output our little layer here. |
||||||
921 | $context['template_layers'] = array(); |
||||||
922 | |||||||
923 | // No funny business allowed |
||||||
924 | $counter = isset($_REQUEST['counter']) ? max(0, (int) $_REQUEST['counter']) : 0; |
||||||
925 | $limit = !empty($modSettings['alerts_per_page']) && (int) $modSettings['alerts_per_page'] < 1000 ? min((int) $modSettings['alerts_per_page'], 1000) : 25; |
||||||
926 | |||||||
927 | $context['unread_alerts'] = array(); |
||||||
928 | if ($counter < $cur_profile['alerts']) |
||||||
929 | { |
||||||
930 | // Now fetch me my unread alerts, pronto! |
||||||
931 | require_once($sourcedir . '/Profile-View.php'); |
||||||
932 | $context['unread_alerts'] = fetch_alerts($memID, false, !empty($counter) ? $cur_profile['alerts'] - $counter : $limit, 0, !isset($_REQUEST['counter'])); |
||||||
0 ignored issues
–
show
It seems like
! empty($counter) ? $cur...s'] - $counter : $limit can also be of type integer ; however, parameter $limit of fetch_alerts() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() 0 of type integer is incompatible with the type array expected by parameter $offset of fetch_alerts() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
933 | |||||||
934 | // This shouldn't happen, but just in case... |
||||||
935 | if (empty($counter) && $cur_profile['alerts'] != count($context['unread_alerts'])) |
||||||
936 | updateMemberData($memID, array('alerts' => count($context['unread_alerts']))); |
||||||
937 | } |
||||||
938 | } |
||||||
939 | |||||||
940 | /** |
||||||
941 | * Load any custom fields for this area... no area means load all, 'summary' loads all public ones. |
||||||
942 | * |
||||||
943 | * @param int $memID The ID of the member |
||||||
944 | * @param string $area Which area to load fields for |
||||||
945 | */ |
||||||
946 | function loadCustomFields($memID, $area = 'summary') |
||||||
947 | { |
||||||
948 | global $context, $txt, $user_profile, $smcFunc, $user_info, $settings, $scripturl; |
||||||
949 | |||||||
950 | // Get the right restrictions in place... |
||||||
951 | $where = 'active = 1'; |
||||||
952 | if (!allowedTo('admin_forum') && $area != 'register') |
||||||
953 | { |
||||||
954 | // If it's the owner they can see two types of private fields, regardless. |
||||||
955 | if ($memID == $user_info['id']) |
||||||
956 | $where .= $area == 'summary' ? ' AND private < 3' : ' AND (private = 0 OR private = 2)'; |
||||||
957 | else |
||||||
958 | $where .= $area == 'summary' ? ' AND private < 2' : ' AND private = 0'; |
||||||
959 | } |
||||||
960 | |||||||
961 | if ($area == 'register') |
||||||
962 | $where .= ' AND show_reg != 0'; |
||||||
963 | elseif ($area != 'summary') |
||||||
964 | $where .= ' AND show_profile = {string:area}'; |
||||||
965 | |||||||
966 | // Load all the relevant fields - and data. |
||||||
967 | $request = $smcFunc['db_query']('', ' |
||||||
968 | SELECT |
||||||
969 | col_name, field_name, field_desc, field_type, field_order, show_reg, field_length, field_options, |
||||||
970 | default_value, bbc, enclose, placement |
||||||
971 | FROM {db_prefix}custom_fields |
||||||
972 | WHERE ' . $where . ' |
||||||
973 | ORDER BY field_order', |
||||||
974 | array( |
||||||
975 | 'area' => $area, |
||||||
976 | ) |
||||||
977 | ); |
||||||
978 | $context['custom_fields'] = array(); |
||||||
979 | $context['custom_fields_required'] = false; |
||||||
980 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||||||
981 | { |
||||||
982 | // Shortcut. |
||||||
983 | $exists = $memID && isset($user_profile[$memID], $user_profile[$memID]['options'][$row['col_name']]); |
||||||
984 | $value = $exists ? $user_profile[$memID]['options'][$row['col_name']] : ''; |
||||||
985 | |||||||
986 | $currentKey = 0; |
||||||
987 | if (!empty($row['field_options'])) |
||||||
988 | { |
||||||
989 | $fieldOptions = explode(',', $row['field_options']); |
||||||
990 | foreach ($fieldOptions as $k => $v) |
||||||
991 | { |
||||||
992 | if (empty($currentKey)) |
||||||
993 | $currentKey = $v === $value ? $k : 0; |
||||||
994 | } |
||||||
995 | } |
||||||
996 | |||||||
997 | // If this was submitted already then make the value the posted version. |
||||||
998 | if (isset($_POST['customfield']) && isset($_POST['customfield'][$row['col_name']])) |
||||||
999 | { |
||||||
1000 | $value = $smcFunc['htmlspecialchars']($_POST['customfield'][$row['col_name']]); |
||||||
1001 | if (in_array($row['field_type'], array('select', 'radio'))) |
||||||
1002 | $value = ($options = explode(',', $row['field_options'])) && isset($options[$value]) ? $options[$value] : ''; |
||||||
1003 | } |
||||||
1004 | |||||||
1005 | // Don't show the "disabled" option for the "gender" field if we are on the "summary" area. |
||||||
1006 | if ($area == 'summary' && $row['col_name'] == 'cust_gender' && $value == '{gender_0}') |
||||||
1007 | continue; |
||||||
1008 | |||||||
1009 | // HTML for the input form. |
||||||
1010 | $output_html = $value; |
||||||
1011 | if ($row['field_type'] == 'check') |
||||||
1012 | { |
||||||
1013 | $true = (!$exists && $row['default_value']) || $value; |
||||||
1014 | $input_html = '<input type="checkbox" name="customfield[' . $row['col_name'] . ']" id="customfield[' . $row['col_name'] . ']"' . ($true ? ' checked' : '') . '>'; |
||||||
1015 | $output_html = $true ? $txt['yes'] : $txt['no']; |
||||||
1016 | } |
||||||
1017 | elseif ($row['field_type'] == 'select') |
||||||
1018 | { |
||||||
1019 | $input_html = '<select name="customfield[' . $row['col_name'] . ']" id="customfield[' . $row['col_name'] . ']"><option value="-1"></option>'; |
||||||
1020 | $options = explode(',', $row['field_options']); |
||||||
1021 | foreach ($options as $k => $v) |
||||||
1022 | { |
||||||
1023 | $true = (!$exists && $row['default_value'] == $v) || $value == $v; |
||||||
1024 | $input_html .= '<option value="' . $k . '"' . ($true ? ' selected' : '') . '>' . tokenTxtReplace($v) . '</option>'; |
||||||
1025 | if ($true) |
||||||
1026 | $output_html = $v; |
||||||
1027 | } |
||||||
1028 | |||||||
1029 | $input_html .= '</select>'; |
||||||
1030 | } |
||||||
1031 | elseif ($row['field_type'] == 'radio') |
||||||
1032 | { |
||||||
1033 | $input_html = '<fieldset>'; |
||||||
1034 | $options = explode(',', $row['field_options']); |
||||||
1035 | foreach ($options as $k => $v) |
||||||
1036 | { |
||||||
1037 | $true = (!$exists && $row['default_value'] == $v) || $value == $v; |
||||||
1038 | $input_html .= '<label for="customfield_' . $row['col_name'] . '_' . $k . '"><input type="radio" name="customfield[' . $row['col_name'] . ']" id="customfield_' . $row['col_name'] . '_' . $k . '" value="' . $k . '"' . ($true ? ' checked' : '') . '>' . tokenTxtReplace($v) . '</label><br>'; |
||||||
1039 | if ($true) |
||||||
1040 | $output_html = $v; |
||||||
1041 | } |
||||||
1042 | $input_html .= '</fieldset>'; |
||||||
1043 | } |
||||||
1044 | elseif ($row['field_type'] == 'text') |
||||||
1045 | { |
||||||
1046 | $input_html = '<input type="text" name="customfield[' . $row['col_name'] . ']" id="customfield[' . $row['col_name'] . ']"' . ($row['field_length'] != 0 ? ' maxlength="' . $row['field_length'] . '"' : '') . ' size="' . ($row['field_length'] == 0 || $row['field_length'] >= 50 ? 50 : ($row['field_length'] > 30 ? 30 : ($row['field_length'] > 10 ? 20 : 10))) . '" value="' . un_htmlspecialchars($value) . '"' . ($row['show_reg'] == 2 ? ' required' : '') . '>'; |
||||||
1047 | } |
||||||
1048 | else |
||||||
1049 | { |
||||||
1050 | @list ($rows, $cols) = @explode(',', $row['default_value']); |
||||||
1051 | $input_html = '<textarea name="customfield[' . $row['col_name'] . ']" id="customfield[' . $row['col_name'] . ']"' . ($row['field_length'] != 0 ? ' maxlength="' . $row['field_length'] . '"' : '') . (!empty($rows) ? ' rows="' . $rows . '"' : '') . (!empty($cols) ? ' cols="' . $cols . '"' : '') . ($row['show_reg'] == 2 ? ' required' : '') . '>' . un_htmlspecialchars($value) . '</textarea>'; |
||||||
1052 | } |
||||||
1053 | |||||||
1054 | // Parse BBCode |
||||||
1055 | if ($row['bbc']) |
||||||
1056 | $output_html = parse_bbc($output_html); |
||||||
1057 | elseif ($row['field_type'] == 'textarea') |
||||||
1058 | // Allow for newlines at least |
||||||
1059 | $output_html = strtr($output_html, array("\n" => '<br>')); |
||||||
1060 | |||||||
1061 | // Enclosing the user input within some other text? |
||||||
1062 | if (!empty($row['enclose']) && !empty($output_html)) |
||||||
1063 | $output_html = strtr($row['enclose'], array( |
||||||
1064 | '{SCRIPTURL}' => $scripturl, |
||||||
1065 | '{IMAGES_URL}' => $settings['images_url'], |
||||||
1066 | '{DEFAULT_IMAGES_URL}' => $settings['default_images_url'], |
||||||
1067 | '{INPUT}' => un_htmlspecialchars($output_html), |
||||||
1068 | '{KEY}' => $currentKey |
||||||
1069 | )); |
||||||
1070 | |||||||
1071 | $context['custom_fields'][] = array( |
||||||
1072 | 'name' => tokenTxtReplace($row['field_name']), |
||||||
1073 | 'desc' => tokenTxtReplace($row['field_desc']), |
||||||
1074 | 'type' => $row['field_type'], |
||||||
1075 | 'order' => $row['field_order'], |
||||||
1076 | 'input_html' => $input_html, |
||||||
1077 | 'output_html' => tokenTxtReplace($output_html), |
||||||
1078 | 'placement' => $row['placement'], |
||||||
1079 | 'colname' => $row['col_name'], |
||||||
1080 | 'value' => $value, |
||||||
1081 | 'show_reg' => $row['show_reg'], |
||||||
1082 | ); |
||||||
1083 | $context['custom_fields_required'] = $context['custom_fields_required'] || $row['show_reg'] == 2; |
||||||
1084 | } |
||||||
1085 | $smcFunc['db_free_result']($request); |
||||||
1086 | |||||||
1087 | call_integration_hook('integrate_load_custom_profile_fields', array($memID, $area)); |
||||||
1088 | } |
||||||
1089 | |||||||
1090 | ?> |