Mercurial > hg > vamp-website
comparison forum/Sources/Profile-Modify.php @ 76:e3e11437ecea website
Add forum code
author | Chris Cannam |
---|---|
date | Sun, 07 Jul 2013 11:25:48 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
75:72f59aa7e503 | 76:e3e11437ecea |
---|---|
1 <?php | |
2 | |
3 /** | |
4 * Simple Machines Forum (SMF) | |
5 * | |
6 * @package SMF | |
7 * @author Simple Machines http://www.simplemachines.org | |
8 * @copyright 2011 Simple Machines | |
9 * @license http://www.simplemachines.org/about/smf/license.php BSD | |
10 * | |
11 * @version 2.0.2 | |
12 */ | |
13 | |
14 if (!defined('SMF')) | |
15 die('Hacking attempt...'); | |
16 | |
17 /* This file has the primary job of showing and editing people's profiles. | |
18 It also allows the user to change some of their or another's preferences, | |
19 and such things. It uses the following functions: | |
20 | |
21 void loadProfileFields(bool force_reload = false) | |
22 // !!! | |
23 | |
24 void setupProfileContext(array fields) | |
25 // !!! | |
26 | |
27 void saveProfileFields() | |
28 // !!! | |
29 | |
30 void saveProfileChanges(array &profile_variables, array &errors, int id_member) | |
31 // !!! | |
32 | |
33 void makeThemeChanges(int id_member, int id_theme) | |
34 // !!! | |
35 | |
36 void makeNotificationChanges(int id_member) | |
37 // !!! | |
38 | |
39 void makeCustomFieldChanges(int id_member, string area, bool sanitize = true) | |
40 // !!! | |
41 | |
42 void editBuddies(int id_member) | |
43 // !!! | |
44 | |
45 void editIgnoreList(int id_member) | |
46 // !!! | |
47 | |
48 void account(int id_member) | |
49 // !!! | |
50 | |
51 void forumProfile(int id_member) | |
52 // !!! | |
53 | |
54 void pmprefs(int id_member) | |
55 // !!! | |
56 | |
57 array getAvatars(string directory, int level) | |
58 // !!! | |
59 | |
60 void theme(int id_member) | |
61 // !!! | |
62 | |
63 void authentication(int id_member, bool saving = false) | |
64 // !!! | |
65 | |
66 void notification(int id_member) | |
67 // !!! | |
68 | |
69 int list_getTopicNotificationCount(int memID) | |
70 // !!! | |
71 | |
72 array list_getTopicNotifications(int start, int items_per_page, string sort, int memID) | |
73 // !!! | |
74 | |
75 array list_getBoardNotifications(int start, int items_per_page, string sort, int memID) | |
76 // !!! | |
77 | |
78 void loadThemeOptions(int id_member) | |
79 // !!! | |
80 | |
81 void ignoreboards(int id_member) | |
82 // !!! | |
83 | |
84 bool profileLoadLanguages() | |
85 // !!! | |
86 | |
87 bool profileLoadGroups() | |
88 // !!! | |
89 | |
90 bool profileLoadSignatureData() | |
91 // !!! | |
92 | |
93 bool profileLoadAvatarData() | |
94 // !!! | |
95 | |
96 bool profileSaveGroups(mixed &value) | |
97 // !!! | |
98 | |
99 mixed profileSaveAvatarData(array &value) | |
100 // !!! | |
101 | |
102 mixed profileValidateSignature(mixed &value) | |
103 // !!! | |
104 | |
105 bool profileValidateEmail(string email, int id_member = none) | |
106 // !!! | |
107 | |
108 void profileReloadUser() | |
109 // !!! | |
110 | |
111 void profileSendActivation() | |
112 // !!! | |
113 | |
114 void groupMembership(int id_member) | |
115 // !!! | |
116 | |
117 mixed groupMembership2(array profile_vars, array post_erros, int id_member) | |
118 // !!! | |
119 | |
120 Adding new fields to the profile: | |
121 --------------------------------------------------------------------------- | |
122 // !!! | |
123 */ | |
124 | |
125 // This defines every profile field known to man. | |
126 function loadProfileFields($force_reload = false) | |
127 { | |
128 global $context, $profile_fields, $txt, $scripturl, $modSettings, $user_info, $old_profile, $smcFunc, $cur_profile, $language; | |
129 | |
130 // Don't load this twice! | |
131 if (!empty($profile_fields) && !$force_reload) | |
132 return; | |
133 | |
134 /* This horrific array defines all the profile fields in the whole world! | |
135 In general each "field" has one array - the key of which is the database column name associated with said field. Each item | |
136 can have the following attributes: | |
137 | |
138 string $type: The type of field this is - valid types are: | |
139 - callback: This is a field which has its own callback mechanism for templating. | |
140 - check: A simple checkbox. | |
141 - hidden: This doesn't have any visual aspects but may have some validity. | |
142 - password: A password box. | |
143 - select: A select box. | |
144 - text: A string of some description. | |
145 | |
146 string $label: The label for this item - default will be $txt[$key] if this isn't set. | |
147 string $subtext: The subtext (Small label) for this item. | |
148 int $size: Optional size for a text area. | |
149 array $input_attr: An array of text strings to be added to the input box for this item. | |
150 string $value: The value of the item. If not set $cur_profile[$key] is assumed. | |
151 string $permission: Permission required for this item (Excluded _any/_own subfix which is applied automatically). | |
152 function $input_validate: A runtime function which validates the element before going to the database. It is passed | |
153 the relevant $_POST element if it exists and should be treated like a reference. | |
154 | |
155 Return types: | |
156 - true: Element can be stored. | |
157 - false: Skip this element. | |
158 - a text string: An error occured - this is the error message. | |
159 | |
160 function $preload: A function that is used to load data required for this element to be displayed. Must return | |
161 true to be displayed at all. | |
162 | |
163 string $cast_type: If set casts the element to a certain type. Valid types (bool, int, float). | |
164 string $save_key: If the index of this element isn't the database column name it can be overriden | |
165 with this string. | |
166 bool $is_dummy: If set then nothing is acted upon for this element. | |
167 bool $enabled: A test to determine whether this is even available - if not is unset. | |
168 string $link_with: Key which links this field to an overall set. | |
169 | |
170 Note that all elements that have a custom input_validate must ensure they set the value of $cur_profile correct to enable | |
171 the changes to be displayed correctly on submit of the form. | |
172 | |
173 */ | |
174 | |
175 $profile_fields = array( | |
176 'aim' => array( | |
177 'type' => 'text', | |
178 'label' => $txt['aim'], | |
179 'subtext' => $txt['your_aim'], | |
180 'size' => 24, | |
181 'value' => strtr(empty($cur_profile['aim']) ? '' : $cur_profile['aim'], '+', ' '), | |
182 'permission' => 'profile_extra', | |
183 'input_validate' => create_function('&$value', ' | |
184 $value = strtr($value, \' \', \'+\'); | |
185 return true; | |
186 '), | |
187 ), | |
188 'avatar_choice' => array( | |
189 'type' => 'callback', | |
190 'callback_func' => 'avatar_select', | |
191 // This handles the permissions too. | |
192 'preload' => 'profileLoadAvatarData', | |
193 'input_validate' => 'profileSaveAvatarData', | |
194 'save_key' => 'avatar', | |
195 ), | |
196 'bday1' => array( | |
197 'type' => 'callback', | |
198 'callback_func' => 'birthdate', | |
199 'permission' => 'profile_extra', | |
200 'preload' => create_function('', ' | |
201 global $cur_profile, $context; | |
202 | |
203 // Split up the birthdate.... | |
204 list ($uyear, $umonth, $uday) = explode(\'-\', empty($cur_profile[\'birthdate\']) || $cur_profile[\'birthdate\'] == \'0001-01-01\' ? \'0000-00-00\' : $cur_profile[\'birthdate\']); | |
205 $context[\'member\'][\'birth_date\'] = array( | |
206 \'year\' => $uyear == \'0004\' ? \'0000\' : $uyear, | |
207 \'month\' => $umonth, | |
208 \'day\' => $uday, | |
209 ); | |
210 | |
211 return true; | |
212 '), | |
213 'input_validate' => create_function('&$value', ' | |
214 global $profile_vars, $cur_profile; | |
215 | |
216 if (isset($_POST[\'bday2\'], $_POST[\'bday3\']) && $value > 0 && $_POST[\'bday2\'] > 0) | |
217 { | |
218 // Set to blank? | |
219 if ((int) $_POST[\'bday3\'] == 1 && (int) $_POST[\'bday2\'] == 1 && (int) $value == 1) | |
220 $value = \'0001-01-01\'; | |
221 else | |
222 $value = checkdate($value, $_POST[\'bday2\'], $_POST[\'bday3\'] < 4 ? 4 : $_POST[\'bday3\']) ? sprintf(\'%04d-%02d-%02d\', $_POST[\'bday3\'] < 4 ? 4 : $_POST[\'bday3\'], $_POST[\'bday1\'], $_POST[\'bday2\']) : \'0001-01-01\'; | |
223 } | |
224 else | |
225 $value = \'0001-01-01\'; | |
226 | |
227 $profile_vars[\'birthdate\'] = $value; | |
228 $cur_profile[\'birthdate\'] = $value; | |
229 return false; | |
230 '), | |
231 ), | |
232 // Setting the birthdate the old style way? | |
233 'birthdate' => array( | |
234 'type' => 'hidden', | |
235 'permission' => 'profile_extra', | |
236 'input_validate' => create_function('&$value', ' | |
237 global $cur_profile; | |
238 // !!! Should we check for this year and tell them they made a mistake :P? (based on coppa at least?) | |
239 if (preg_match(\'/(\d{4})[\-\., ](\d{2})[\-\., ](\d{2})/\', $value, $dates) === 1) | |
240 { | |
241 $value = checkdate($dates[2], $dates[3], $dates[1] < 4 ? 4 : $dates[1]) ? sprintf(\'%04d-%02d-%02d\', $dates[1] < 4 ? 4 : $dates[1], $dates[2], $dates[3]) : \'0001-01-01\'; | |
242 return true; | |
243 } | |
244 else | |
245 { | |
246 $value = empty($cur_profile[\'birthdate\']) ? \'0001-01-01\' : $cur_profile[\'birthdate\']; | |
247 return false; | |
248 } | |
249 '), | |
250 ), | |
251 'date_registered' => array( | |
252 'type' => 'text', | |
253 'value' => empty($cur_profile['date_registered']) ? $txt['not_applicable'] : strftime('%Y-%m-%d', $cur_profile['date_registered'] + ($user_info['time_offset'] + $modSettings['time_offset']) * 3600), | |
254 'label' => $txt['date_registered'], | |
255 'log_change' => true, | |
256 'permission' => 'moderate_forum', | |
257 'input_validate' => create_function('&$value', ' | |
258 global $txt, $user_info, $modSettings, $cur_profile, $context; | |
259 | |
260 // Bad date! Go try again - please? | |
261 if (($value = strtotime($value)) === -1) | |
262 { | |
263 $value = $cur_profile[\'date_registered\']; | |
264 return $txt[\'invalid_registration\'] . \' \' . strftime(\'%d %b %Y \' . (strpos($user_info[\'time_format\'], \'%H\') !== false ? \'%I:%M:%S %p\' : \'%H:%M:%S\'), forum_time(false)); | |
265 } | |
266 // As long as it doesn\'t equal "N/A"... | |
267 elseif ($value != $txt[\'not_applicable\'] && $value != strtotime(strftime(\'%Y-%m-%d\', $cur_profile[\'date_registered\'] + ($user_info[\'time_offset\'] + $modSettings[\'time_offset\']) * 3600))) | |
268 $value = $value - ($user_info[\'time_offset\'] + $modSettings[\'time_offset\']) * 3600; | |
269 else | |
270 $value = $cur_profile[\'date_registered\']; | |
271 | |
272 return true; | |
273 '), | |
274 ), | |
275 'email_address' => array( | |
276 'type' => 'text', | |
277 'label' => $txt['email'], | |
278 'subtext' => $txt['valid_email'], | |
279 'log_change' => true, | |
280 'permission' => 'profile_identity', | |
281 'input_validate' => create_function('&$value', ' | |
282 global $context, $old_profile, $context, $profile_vars, $sourcedir, $modSettings; | |
283 | |
284 if (strtolower($value) == strtolower($old_profile[\'email_address\'])) | |
285 return false; | |
286 | |
287 $isValid = profileValidateEmail($value, $context[\'id_member\']); | |
288 | |
289 // Do they need to revalidate? If so schedule the function! | |
290 if ($isValid === true && !empty($modSettings[\'send_validation_onChange\']) && !allowedTo(\'moderate_forum\')) | |
291 { | |
292 require_once($sourcedir . \'/Subs-Members.php\'); | |
293 $profile_vars[\'validation_code\'] = generateValidationCode(); | |
294 $profile_vars[\'is_activated\'] = 2; | |
295 $context[\'profile_execute_on_save\'][] = \'profileSendActivation\'; | |
296 unset($context[\'profile_execute_on_save\'][\'reload_user\']); | |
297 } | |
298 | |
299 return $isValid; | |
300 '), | |
301 ), | |
302 'gender' => array( | |
303 'type' => 'select', | |
304 'cast_type' => 'int', | |
305 'options' => 'return array(0 => \'\', 1 => $txt[\'male\'], 2 => $txt[\'female\']);', | |
306 'label' => $txt['gender'], | |
307 'permission' => 'profile_extra', | |
308 ), | |
309 'hide_email' => array( | |
310 'type' => 'check', | |
311 'value' => empty($cur_profile['hide_email']) ? true : false, | |
312 'label' => $txt['allow_user_email'], | |
313 'permission' => 'profile_identity', | |
314 'input_validate' => create_function('&$value', ' | |
315 $value = $value == 0 ? 1 : 0; | |
316 | |
317 return true; | |
318 '), | |
319 ), | |
320 'icq' => array( | |
321 'type' => 'text', | |
322 'label' => $txt['icq'], | |
323 'subtext' => $txt['your_icq'], | |
324 'size' => 24, | |
325 'permission' => 'profile_extra', | |
326 // Need to make sure ICQ doesn't equal 0. | |
327 'input_validate' => create_function('&$value', ' | |
328 if (empty($value)) | |
329 $value = \'\'; | |
330 else | |
331 $value = (int) $value; | |
332 return true; | |
333 '), | |
334 ), | |
335 // Selecting group membership is a complicated one so we treat it separate! | |
336 'id_group' => array( | |
337 'type' => 'callback', | |
338 'callback_func' => 'group_manage', | |
339 'permission' => 'manage_membergroups', | |
340 'preload' => 'profileLoadGroups', | |
341 'log_change' => true, | |
342 'input_validate' => 'profileSaveGroups', | |
343 ), | |
344 'id_theme' => array( | |
345 'type' => 'callback', | |
346 'callback_func' => 'theme_pick', | |
347 'permission' => 'profile_extra', | |
348 'enabled' => $modSettings['theme_allow'] || allowedTo('admin_forum'), | |
349 'preload' => create_function('', ' | |
350 global $smcFunc, $context, $cur_profile, $txt; | |
351 | |
352 $request = $smcFunc[\'db_query\'](\'\', \' | |
353 SELECT value | |
354 FROM {db_prefix}themes | |
355 WHERE id_theme = {int:id_theme} | |
356 AND variable = {string:variable} | |
357 LIMIT 1\', array( | |
358 \'id_theme\' => $cur_profile[\'id_theme\'], | |
359 \'variable\' => \'name\', | |
360 ) | |
361 ); | |
362 list ($name) = $smcFunc[\'db_fetch_row\']($request); | |
363 $smcFunc[\'db_free_result\']($request); | |
364 | |
365 $context[\'member\'][\'theme\'] = array( | |
366 \'id\' => $cur_profile[\'id_theme\'], | |
367 \'name\' => empty($cur_profile[\'id_theme\']) ? $txt[\'theme_forum_default\'] : $name | |
368 ); | |
369 return true; | |
370 '), | |
371 'input_validate' => create_function('&$value', ' | |
372 $value = (int) $value; | |
373 return true; | |
374 '), | |
375 ), | |
376 'karma_good' => array( | |
377 'type' => 'callback', | |
378 'callback_func' => 'karma_modify', | |
379 'permission' => 'admin_forum', | |
380 // Set karma_bad too! | |
381 'input_validate' => create_function('&$value', ' | |
382 global $profile_vars, $cur_profile; | |
383 | |
384 $value = (int) $value; | |
385 if (isset($_POST[\'karma_bad\'])) | |
386 { | |
387 $profile_vars[\'karma_bad\'] = $_POST[\'karma_bad\'] != \'\' ? (int) $_POST[\'karma_bad\'] : 0; | |
388 $cur_profile[\'karma_bad\'] = $_POST[\'karma_bad\'] != \'\' ? (int) $_POST[\'karma_bad\'] : 0; | |
389 } | |
390 return true; | |
391 '), | |
392 'preload' => create_function('', ' | |
393 global $context, $cur_profile; | |
394 | |
395 $context[\'member\'][\'karma\'][\'good\'] = $cur_profile[\'karma_good\']; | |
396 $context[\'member\'][\'karma\'][\'bad\'] = $cur_profile[\'karma_bad\']; | |
397 | |
398 return true; | |
399 '), | |
400 'enabled' => !empty($modSettings['karmaMode']), | |
401 ), | |
402 'lngfile' => array( | |
403 'type' => 'select', | |
404 'options' => 'return $context[\'profile_languages\'];', | |
405 'label' => $txt['preferred_language'], | |
406 'permission' => 'profile_identity', | |
407 'preload' => 'profileLoadLanguages', | |
408 'enabled' => !empty($modSettings['userLanguage']), | |
409 'value' => empty($cur_profile['lngfile']) ? $language : $cur_profile['lngfile'], | |
410 'input_validate' => create_function('&$value', ' | |
411 global $context, $cur_profile; | |
412 | |
413 // Load the languages. | |
414 profileLoadLanguages(); | |
415 | |
416 if (isset($context[\'profile_languages\'][$value])) | |
417 { | |
418 if ($context[\'user\'][\'is_owner\'] && empty($context[\'password_auth_failed\'])) | |
419 $_SESSION[\'language\'] = $value; | |
420 return true; | |
421 } | |
422 else | |
423 { | |
424 $value = $cur_profile[\'lngfile\']; | |
425 return false; | |
426 } | |
427 '), | |
428 ), | |
429 'location' => array( | |
430 'type' => 'text', | |
431 'label' => $txt['location'], | |
432 'log_change' => true, | |
433 'size' => 50, | |
434 'permission' => 'profile_extra', | |
435 ), | |
436 // The username is not always editable - so adjust it as such. | |
437 'member_name' => array( | |
438 'type' => allowedTo('admin_forum') && isset($_GET['changeusername']) ? 'text' : 'label', | |
439 'label' => $txt['username'], | |
440 'subtext' => allowedTo('admin_forum') && !isset($_GET['changeusername']) ? '(<a href="' . $scripturl . '?action=profile;u=' . $context['id_member'] . ';area=account;changeusername" style="font-style: italic;">' . $txt['username_change'] . '</a>)' : '', | |
441 'log_change' => true, | |
442 'permission' => 'profile_identity', | |
443 'prehtml' => allowedTo('admin_forum') && isset($_GET['changeusername']) ? '<div class="alert">' . $txt['username_warning'] . '</div>' : '', | |
444 'input_validate' => create_function('&$value', ' | |
445 global $sourcedir, $context, $user_info, $cur_profile; | |
446 | |
447 if (allowedTo(\'admin_forum\')) | |
448 { | |
449 // We\'ll need this... | |
450 require_once($sourcedir . \'/Subs-Auth.php\'); | |
451 | |
452 // Maybe they are trying to change their password as well? | |
453 $resetPassword = true; | |
454 if (isset($_POST[\'passwrd1\']) && $_POST[\'passwrd1\'] != \'\' && isset($_POST[\'passwrd2\']) && $_POST[\'passwrd1\'] == $_POST[\'passwrd2\'] && validatePassword($_POST[\'passwrd1\'], $value, array($cur_profile[\'real_name\'], $user_info[\'username\'], $user_info[\'name\'], $user_info[\'email\'])) == null) | |
455 $resetPassword = false; | |
456 | |
457 // Do the reset... this will send them an email too. | |
458 if ($resetPassword) | |
459 resetPassword($context[\'id_member\'], $value); | |
460 elseif ($value !== null) | |
461 { | |
462 validateUsername($context[\'id_member\'], $value); | |
463 updateMemberData($context[\'id_member\'], array(\'member_name\' => $value)); | |
464 } | |
465 } | |
466 return false; | |
467 '), | |
468 ), | |
469 'msn' => array( | |
470 'type' => 'text', | |
471 'label' => $txt['msn'], | |
472 'subtext' => $txt['msn_email_address'], | |
473 'size' => 24, | |
474 'permission' => 'profile_extra', | |
475 'input_validate' => create_function('&$value', ' | |
476 global $cur_profile; | |
477 // Make sure the msn one is an email address, not something like \'none\' :P. | |
478 if ($value != \'\' && preg_match(\'~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\\\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~\', $value) == 0) | |
479 { | |
480 $value = $cur_profile[\'msn\']; | |
481 return false; | |
482 } | |
483 return true; | |
484 '), | |
485 ), | |
486 'passwrd1' => array( | |
487 'type' => 'password', | |
488 'label' => $txt['choose_pass'], | |
489 'subtext' => $txt['password_strength'], | |
490 'size' => 20, | |
491 'value' => '', | |
492 'enabled' => empty($cur_profile['openid_uri']), | |
493 'permission' => 'profile_identity', | |
494 'save_key' => 'passwd', | |
495 // Note this will only work if passwrd2 also exists! | |
496 'input_validate' => create_function('&$value', ' | |
497 global $sourcedir, $user_info, $smcFunc, $cur_profile; | |
498 | |
499 // If we didn\'t try it then ignore it! | |
500 if ($value == \'\') | |
501 return false; | |
502 | |
503 // Do the two entries for the password even match? | |
504 if (!isset($_POST[\'passwrd2\']) || $value != $_POST[\'passwrd2\']) | |
505 return \'bad_new_password\'; | |
506 | |
507 // Let\'s get the validation function into play... | |
508 require_once($sourcedir . \'/Subs-Auth.php\'); | |
509 $passwordErrors = validatePassword($value, $cur_profile[\'member_name\'], array($cur_profile[\'real_name\'], $user_info[\'username\'], $user_info[\'name\'], $user_info[\'email\'])); | |
510 | |
511 // Were there errors? | |
512 if ($passwordErrors != null) | |
513 return \'password_\' . $passwordErrors; | |
514 | |
515 // Set up the new password variable... ready for storage. | |
516 $value = sha1(strtolower($cur_profile[\'member_name\']) . un_htmlspecialchars($value)); | |
517 return true; | |
518 '), | |
519 ), | |
520 'passwrd2' => array( | |
521 'type' => 'password', | |
522 'label' => $txt['verify_pass'], | |
523 'enabled' => empty($cur_profile['openid_uri']), | |
524 'size' => 20, | |
525 'value' => '', | |
526 'permission' => 'profile_identity', | |
527 'is_dummy' => true, | |
528 ), | |
529 'personal_text' => array( | |
530 'type' => 'text', | |
531 'label' => $txt['personal_text'], | |
532 'log_change' => true, | |
533 'input_attr' => array('maxlength="50"'), | |
534 'size' => 50, | |
535 'permission' => 'profile_extra', | |
536 ), | |
537 // This does ALL the pm settings | |
538 'pm_prefs' => array( | |
539 'type' => 'callback', | |
540 'callback_func' => 'pm_settings', | |
541 'permission' => 'pm_read', | |
542 'preload' => create_function('', ' | |
543 global $context, $cur_profile; | |
544 | |
545 $context[\'display_mode\'] = $cur_profile[\'pm_prefs\'] & 3; | |
546 $context[\'send_email\'] = $cur_profile[\'pm_email_notify\']; | |
547 $context[\'receive_from\'] = !empty($cur_profile[\'pm_receive_from\']) ? $cur_profile[\'pm_receive_from\'] : 0; | |
548 | |
549 return true; | |
550 '), | |
551 'input_validate' => create_function('&$value', ' | |
552 global $cur_profile, $profile_vars; | |
553 | |
554 // Simple validate and apply the two "sub settings" | |
555 $value = max(min($value, 2), 0); | |
556 | |
557 $cur_profile[\'pm_email_notify\'] = $profile_vars[\'pm_email_notify\'] = max(min((int) $_POST[\'pm_email_notify\'], 2), 0); | |
558 $cur_profile[\'pm_receive_from\'] = $profile_vars[\'pm_receive_from\'] = max(min((int) $_POST[\'pm_receive_from\'], 4), 0); | |
559 | |
560 return true; | |
561 '), | |
562 ), | |
563 'posts' => array( | |
564 'type' => 'int', | |
565 'label' => $txt['profile_posts'], | |
566 'log_change' => true, | |
567 'size' => 7, | |
568 'permission' => 'moderate_forum', | |
569 'input_validate' => create_function('&$value', ' | |
570 $value = $value != \'\' ? strtr($value, array(\',\' => \'\', \'.\' => \'\', \' \' => \'\')) : 0; | |
571 return true; | |
572 '), | |
573 ), | |
574 'real_name' => array( | |
575 'type' => !empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum') ? 'text' : 'label', | |
576 'label' => $txt['name'], | |
577 'subtext' => $txt['display_name_desc'], | |
578 'log_change' => true, | |
579 'input_attr' => array('maxlength="60"'), | |
580 'permission' => 'profile_identity', | |
581 'enabled' => !empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum'), | |
582 'input_validate' => create_function('&$value', ' | |
583 global $context, $smcFunc, $sourcedir, $cur_profile; | |
584 | |
585 $value = trim(preg_replace(\'~[\s]~\' . ($context[\'utf8\'] ? \'u\' : \'\'), \' \', $value)); | |
586 | |
587 if (trim($value) == \'\') | |
588 return \'no_name\'; | |
589 elseif ($smcFunc[\'strlen\']($value) > 60) | |
590 return \'name_too_long\'; | |
591 elseif ($cur_profile[\'real_name\'] != $value) | |
592 { | |
593 require_once($sourcedir . \'/Subs-Members.php\'); | |
594 if (isReservedName($value, $context[\'id_member\'])) | |
595 return \'name_taken\'; | |
596 } | |
597 return true; | |
598 '), | |
599 ), | |
600 'secret_question' => array( | |
601 'type' => 'text', | |
602 'label' => $txt['secret_question'], | |
603 'subtext' => $txt['secret_desc'], | |
604 'size' => 50, | |
605 'permission' => 'profile_identity', | |
606 ), | |
607 'secret_answer' => array( | |
608 'type' => 'text', | |
609 'label' => $txt['secret_answer'], | |
610 'subtext' => $txt['secret_desc2'], | |
611 'size' => 20, | |
612 'postinput' => '<span class="smalltext" style="margin-left: 4ex;"><a href="' . $scripturl . '?action=helpadmin;help=secret_why_blank" onclick="return reqWin(this.href);">' . $txt['secret_why_blank'] . '</a></span>', | |
613 'value' => '', | |
614 'permission' => 'profile_identity', | |
615 'input_validate' => create_function('&$value', ' | |
616 $value = $value != \'\' ? md5($value) : \'\'; | |
617 return true; | |
618 '), | |
619 ), | |
620 'signature' => array( | |
621 'type' => 'callback', | |
622 'callback_func' => 'signature_modify', | |
623 'permission' => 'profile_extra', | |
624 'enabled' => substr($modSettings['signature_settings'], 0, 1) == 1, | |
625 'preload' => 'profileLoadSignatureData', | |
626 'input_validate' => 'profileValidateSignature', | |
627 ), | |
628 'show_online' => array( | |
629 'type' => 'check', | |
630 'label' => $txt['show_online'], | |
631 'permission' => 'profile_identity', | |
632 'enabled' => !empty($modSettings['allow_hideOnline']) || allowedTo('moderate_forum'), | |
633 ), | |
634 'smiley_set' => array( | |
635 'type' => 'callback', | |
636 'callback_func' => 'smiley_pick', | |
637 'enabled' => !empty($modSettings['smiley_sets_enable']), | |
638 'permission' => 'profile_extra', | |
639 'preload' => create_function('', ' | |
640 global $modSettings, $context, $txt, $cur_profile; | |
641 | |
642 $context[\'member\'][\'smiley_set\'][\'id\'] = empty($cur_profile[\'smiley_set\']) ? \'\' : $cur_profile[\'smiley_set\']; | |
643 $context[\'smiley_sets\'] = explode(\',\', \'none,,\' . $modSettings[\'smiley_sets_known\']); | |
644 $set_names = explode("\n", $txt[\'smileys_none\'] . "\n" . $txt[\'smileys_forum_board_default\'] . "\n" . $modSettings[\'smiley_sets_names\']); | |
645 foreach ($context[\'smiley_sets\'] as $i => $set) | |
646 { | |
647 $context[\'smiley_sets\'][$i] = array( | |
648 \'id\' => htmlspecialchars($set), | |
649 \'name\' => htmlspecialchars($set_names[$i]), | |
650 \'selected\' => $set == $context[\'member\'][\'smiley_set\'][\'id\'] | |
651 ); | |
652 | |
653 if ($context[\'smiley_sets\'][$i][\'selected\']) | |
654 $context[\'member\'][\'smiley_set\'][\'name\'] = $set_names[$i]; | |
655 } | |
656 return true; | |
657 '), | |
658 'input_validate' => create_function('&$value', ' | |
659 global $modSettings; | |
660 | |
661 $smiley_sets = explode(\',\', $modSettings[\'smiley_sets_known\']); | |
662 if (!in_array($value, $smiley_sets) && $value != \'none\') | |
663 $value = \'\'; | |
664 return true; | |
665 '), | |
666 ), | |
667 // Pretty much a dummy entry - it populates all the theme settings. | |
668 'theme_settings' => array( | |
669 'type' => 'callback', | |
670 'callback_func' => 'theme_settings', | |
671 'permission' => 'profile_extra', | |
672 'is_dummy' => true, | |
673 'preload' => create_function('', ' | |
674 loadLanguage(\'Settings\'); | |
675 return true; | |
676 '), | |
677 ), | |
678 'time_format' => array( | |
679 'type' => 'callback', | |
680 'callback_func' => 'timeformat_modify', | |
681 'permission' => 'profile_extra', | |
682 'preload' => create_function('', ' | |
683 global $context, $user_info, $txt, $cur_profile, $modSettings; | |
684 | |
685 $context[\'easy_timeformats\'] = array( | |
686 array(\'format\' => \'\', \'title\' => $txt[\'timeformat_default\']), | |
687 array(\'format\' => \'%B %d, %Y, %I:%M:%S %p\', \'title\' => $txt[\'timeformat_easy1\']), | |
688 array(\'format\' => \'%B %d, %Y, %H:%M:%S\', \'title\' => $txt[\'timeformat_easy2\']), | |
689 array(\'format\' => \'%Y-%m-%d, %H:%M:%S\', \'title\' => $txt[\'timeformat_easy3\']), | |
690 array(\'format\' => \'%d %B %Y, %H:%M:%S\', \'title\' => $txt[\'timeformat_easy4\']), | |
691 array(\'format\' => \'%d-%m-%Y, %H:%M:%S\', \'title\' => $txt[\'timeformat_easy5\']) | |
692 ); | |
693 | |
694 $context[\'member\'][\'time_format\'] = $cur_profile[\'time_format\']; | |
695 $context[\'current_forum_time\'] = timeformat(time() - $user_info[\'time_offset\'] * 3600, false); | |
696 $context[\'current_forum_time_js\'] = strftime(\'%Y,\' . ((int) strftime(\'%m\', time() + $modSettings[\'time_offset\'] * 3600) - 1) . \',%d,%H,%M,%S\', time() + $modSettings[\'time_offset\'] * 3600); | |
697 $context[\'current_forum_time_hour\'] = (int) strftime(\'%H\', forum_time(false)); | |
698 return true; | |
699 '), | |
700 ), | |
701 'time_offset' => array( | |
702 'type' => 'callback', | |
703 'callback_func' => 'timeoffset_modify', | |
704 'permission' => 'profile_extra', | |
705 'preload' => create_function('', ' | |
706 global $context, $cur_profile; | |
707 $context[\'member\'][\'time_offset\'] = $cur_profile[\'time_offset\']; | |
708 return true; | |
709 '), | |
710 'input_validate' => create_function('&$value', ' | |
711 // Validate the time_offset... | |
712 $value = (float) strtr($value, \',\', \'.\'); | |
713 | |
714 if ($value < -23.5 || $value > 23.5) | |
715 return \'bad_offset\'; | |
716 | |
717 return true; | |
718 '), | |
719 ), | |
720 'usertitle' => array( | |
721 'type' => 'text', | |
722 'label' => $txt['custom_title'], | |
723 'log_change' => true, | |
724 'size' => 50, | |
725 'permission' => 'profile_title', | |
726 'enabled' => !empty($modSettings['titlesEnable']), | |
727 ), | |
728 'website_title' => array( | |
729 'type' => 'text', | |
730 'label' => $txt['website_title'], | |
731 'subtext' => $txt['include_website_url'], | |
732 'size' => 50, | |
733 'permission' => 'profile_extra', | |
734 'link_with' => 'website', | |
735 ), | |
736 'website_url' => array( | |
737 'type' => 'text', | |
738 'label' => $txt['website_url'], | |
739 'subtext' => $txt['complete_url'], | |
740 'size' => 50, | |
741 'permission' => 'profile_extra', | |
742 // Fix the URL... | |
743 'input_validate' => create_function('&$value', ' | |
744 | |
745 if (strlen(trim($value)) > 0 && strpos($value, \'://\') === false) | |
746 $value = \'http://\' . $value; | |
747 if (strlen($value) < 8 || (substr($value, 0, 7) !== \'http://\' && substr($value, 0, 8) !== \'https://\')) | |
748 $value = \'\'; | |
749 return true; | |
750 '), | |
751 'link_with' => 'website', | |
752 ), | |
753 'yim' => array( | |
754 'type' => 'text', | |
755 'label' => $txt['yim'], | |
756 'subtext' => $txt['your_yim'], | |
757 'size' => 24, | |
758 'input_attr' => array('maxlength="32"'), | |
759 'permission' => 'profile_extra', | |
760 ), | |
761 ); | |
762 | |
763 $disabled_fields = !empty($modSettings['disabled_profile_fields']) ? explode(',', $modSettings['disabled_profile_fields']) : array(); | |
764 // For each of the above let's take out the bits which don't apply - to save memory and security! | |
765 foreach ($profile_fields as $key => $field) | |
766 { | |
767 // Do we have permission to do this? | |
768 if (isset($field['permission']) && !allowedTo(($context['user']['is_owner'] ? array($field['permission'] . '_own', $field['permission'] . '_any') : $field['permission'] . '_any')) && !allowedTo($field['permission'])) | |
769 unset($profile_fields[$key]); | |
770 | |
771 // Is it enabled? | |
772 if (isset($field['enabled']) && !$field['enabled']) | |
773 unset($profile_fields[$key]); | |
774 | |
775 // Is it specifically disabled? | |
776 if (in_array($key, $disabled_fields) || (isset($field['link_with']) && in_array($field['link_with'], $disabled_fields))) | |
777 unset($profile_fields[$key]); | |
778 } | |
779 } | |
780 | |
781 // Setup the context for a page load! | |
782 function setupProfileContext($fields) | |
783 { | |
784 global $profile_fields, $context, $cur_profile, $smcFunc, $txt; | |
785 | |
786 // Make sure we have this! | |
787 loadProfileFields(true); | |
788 | |
789 // First check for any linked sets. | |
790 foreach ($profile_fields as $key => $field) | |
791 if (isset($field['link_with']) && in_array($field['link_with'], $fields)) | |
792 $fields[] = $key; | |
793 | |
794 // Some default bits. | |
795 $context['profile_prehtml'] = ''; | |
796 $context['profile_posthtml'] = ''; | |
797 $context['profile_javascript'] = ''; | |
798 $context['profile_onsubmit_javascript'] = ''; | |
799 | |
800 $i = 0; | |
801 $last_type = ''; | |
802 foreach ($fields as $key => $field) | |
803 { | |
804 if (isset($profile_fields[$field])) | |
805 { | |
806 // Shortcut. | |
807 $cur_field = &$profile_fields[$field]; | |
808 | |
809 // Does it have a preload and does that preload succeed? | |
810 if (isset($cur_field['preload']) && !$cur_field['preload']()) | |
811 continue; | |
812 | |
813 // If this is anything but complex we need to do more cleaning! | |
814 if ($cur_field['type'] != 'callback' && $cur_field['type'] != 'hidden') | |
815 { | |
816 if (!isset($cur_field['label'])) | |
817 $cur_field['label'] = isset($txt[$field]) ? $txt[$field] : $field; | |
818 | |
819 // Everything has a value! | |
820 if (!isset($cur_field['value'])) | |
821 { | |
822 $cur_field['value'] = isset($cur_profile[$field]) ? $cur_profile[$field] : ''; | |
823 } | |
824 | |
825 // Any input attributes? | |
826 $cur_field['input_attr'] = !empty($cur_field['input_attr']) ? implode(',', $cur_field['input_attr']) : ''; | |
827 } | |
828 | |
829 // Was there an error with this field on posting? | |
830 if (isset($context['profile_errors'][$field])) | |
831 $cur_field['is_error'] = true; | |
832 | |
833 // Any javascript stuff? | |
834 if (!empty($cur_field['js_submit'])) | |
835 $context['profile_onsubmit_javascript'] .= $cur_field['js_submit']; | |
836 if (!empty($cur_field['js'])) | |
837 $context['profile_javascript'] .= $cur_field['js']; | |
838 | |
839 // Any template stuff? | |
840 if (!empty($cur_field['prehtml'])) | |
841 $context['profile_prehtml'] .= $cur_field['prehtml']; | |
842 if (!empty($cur_field['posthtml'])) | |
843 $context['profile_posthtml'] .= $cur_field['posthtml']; | |
844 | |
845 // Finally put it into context? | |
846 if ($cur_field['type'] != 'hidden') | |
847 { | |
848 $last_type = $cur_field['type']; | |
849 $context['profile_fields'][$field] = &$profile_fields[$field]; | |
850 } | |
851 } | |
852 // Bodge in a line break - without doing two in a row ;) | |
853 elseif ($field == 'hr' && $last_type != 'hr' && $last_type != '') | |
854 { | |
855 $last_type = 'hr'; | |
856 $context['profile_fields'][$i++]['type'] = 'hr'; | |
857 } | |
858 } | |
859 | |
860 // Free up some memory. | |
861 unset($profile_fields); | |
862 } | |
863 | |
864 // Save the profile changes. | |
865 function saveProfileFields() | |
866 { | |
867 global $profile_fields, $profile_vars, $context, $old_profile, $post_errors, $sourcedir, $modSettings, $cur_profile, $smcFunc; | |
868 | |
869 // Load them up. | |
870 loadProfileFields(); | |
871 | |
872 // This makes things easier... | |
873 $old_profile = $cur_profile; | |
874 | |
875 // This allows variables to call activities when they save - by default just to reload their settings | |
876 $context['profile_execute_on_save'] = array(); | |
877 if ($context['user']['is_owner']) | |
878 $context['profile_execute_on_save']['reload_user'] = 'profileReloadUser'; | |
879 | |
880 // Assume we log nothing. | |
881 $context['log_changes'] = array(); | |
882 | |
883 // Cycle through the profile fields working out what to do! | |
884 foreach ($profile_fields as $key => $field) | |
885 { | |
886 if (!isset($_POST[$key]) || !empty($field['is_dummy'])) | |
887 continue; | |
888 | |
889 // What gets updated? | |
890 $db_key = isset($field['save_key']) ? $field['save_key'] : $key; | |
891 | |
892 // Right - we have something that is enabled, we can act upon and has a value posted to it. Does it have a validation function? | |
893 if (isset($field['input_validate'])) | |
894 { | |
895 $is_valid = $field['input_validate']($_POST[$key]); | |
896 // An error occured - set it as such! | |
897 if ($is_valid !== true) | |
898 { | |
899 // Is this an actual error? | |
900 if ($is_valid !== false) | |
901 { | |
902 $post_errors[$key] = $is_valid; | |
903 $profile_fields[$key]['is_error'] = $is_valid; | |
904 } | |
905 // Retain the old value. | |
906 $cur_profile[$key] = $_POST[$key]; | |
907 continue; | |
908 } | |
909 } | |
910 | |
911 // Are we doing a cast? | |
912 $field['cast_type'] = empty($field['cast_type']) ? $field['type'] : $field['cast_type']; | |
913 | |
914 // Finally, clean up certain types. | |
915 if ($field['cast_type'] == 'int') | |
916 $_POST[$key] = (int) $_POST[$key]; | |
917 elseif ($field['cast_type'] == 'float') | |
918 $_POST[$key] = (float) $_POST[$key]; | |
919 elseif ($field['cast_type'] == 'check') | |
920 $_POST[$key] = !empty($_POST[$key]) ? 1 : 0; | |
921 | |
922 // If we got here we're doing OK. | |
923 if ($field['type'] != 'hidden' && (!isset($old_profile[$key]) || $_POST[$key] != $old_profile[$key])) | |
924 { | |
925 // Set the save variable. | |
926 $profile_vars[$db_key] = $_POST[$key]; | |
927 // And update the user profile. | |
928 $cur_profile[$key] = $_POST[$key]; | |
929 | |
930 // Are we logging it? | |
931 if (!empty($field['log_change']) && isset($old_profile[$key])) | |
932 $context['log_changes'][$key] = array( | |
933 'previous' => $old_profile[$key], | |
934 'new' => $_POST[$key], | |
935 ); | |
936 } | |
937 | |
938 // Logging group changes are a bit different... | |
939 if ($key == 'id_group' && $field['log_change']) | |
940 { | |
941 profileLoadGroups(); | |
942 | |
943 // Any changes to primary group? | |
944 if ($_POST['id_group'] != $old_profile['id_group']) | |
945 { | |
946 $context['log_changes']['id_group'] = array( | |
947 'previous' => !empty($old_profile[$key]) && isset($context['member_groups'][$old_profile[$key]]) ? $context['member_groups'][$old_profile[$key]]['name'] : '', | |
948 'new' => !empty($_POST[$key]) && isset($context['member_groups'][$_POST[$key]]) ? $context['member_groups'][$_POST[$key]]['name'] : '', | |
949 ); | |
950 } | |
951 | |
952 // Prepare additional groups for comparison. | |
953 $additional_groups = array( | |
954 'previous' => !empty($old_profile['additional_groups']) ? explode(',', $old_profile['additional_groups']) : array(), | |
955 'new' => !empty($_POST['additional_groups']) ? array_diff($_POST['additional_groups'], array(0)) : array(), | |
956 ); | |
957 | |
958 sort($additional_groups['previous']); | |
959 sort($additional_groups['new']); | |
960 | |
961 // What about additional groups? | |
962 if ($additional_groups['previous'] != $additional_groups['new']) | |
963 { | |
964 foreach ($additional_groups as $type => $groups) | |
965 { | |
966 foreach ($groups as $id => $group) | |
967 { | |
968 if (isset($context['member_groups'][$group])) | |
969 $additional_groups[$type][$id] = $context['member_groups'][$group]['name']; | |
970 else | |
971 unset($additional_groups[$type][$id]); | |
972 } | |
973 $additional_groups[$type] = implode(', ', $additional_groups[$type]); | |
974 } | |
975 | |
976 $context['log_changes']['additional_groups'] = $additional_groups; | |
977 } | |
978 } | |
979 } | |
980 | |
981 //!!! Temporary | |
982 if ($context['user']['is_owner']) | |
983 $changeOther = allowedTo(array('profile_extra_any', 'profile_extra_own')); | |
984 else | |
985 $changeOther = allowedTo('profile_extra_any'); | |
986 if ($changeOther && empty($post_errors)) | |
987 { | |
988 makeThemeChanges($context['id_member'], isset($_POST['id_theme']) ? (int) $_POST['id_theme'] : $old_profile['id_theme']); | |
989 if (!empty($_REQUEST['sa'])) | |
990 makeCustomFieldChanges($context['id_member'], $_REQUEST['sa'], false); | |
991 } | |
992 | |
993 // Free memory! | |
994 unset($profile_fields); | |
995 } | |
996 | |
997 // Save the profile changes.... | |
998 function saveProfileChanges(&$profile_vars, &$post_errors, $memID) | |
999 { | |
1000 global $user_info, $txt, $modSettings, $user_profile; | |
1001 global $context, $settings, $sourcedir; | |
1002 global $smcFunc; | |
1003 | |
1004 // These make life easier.... | |
1005 $old_profile = &$user_profile[$memID]; | |
1006 | |
1007 // Permissions... | |
1008 if ($context['user']['is_owner']) | |
1009 { | |
1010 $changeIdentity = allowedTo(array('profile_identity_any', 'profile_identity_own')); | |
1011 $changeOther = allowedTo(array('profile_extra_any', 'profile_extra_own')); | |
1012 } | |
1013 else | |
1014 { | |
1015 $changeIdentity = allowedTo('profile_identity_any'); | |
1016 $changeOther = allowedTo('profile_extra_any'); | |
1017 } | |
1018 | |
1019 // Arrays of all the changes - makes things easier. | |
1020 $profile_bools = array( | |
1021 'notify_announcements', 'notify_send_body', | |
1022 ); | |
1023 $profile_ints = array( | |
1024 'notify_regularity', | |
1025 'notify_types', | |
1026 ); | |
1027 $profile_floats = array( | |
1028 ); | |
1029 $profile_strings = array( | |
1030 'buddy_list', | |
1031 'ignore_boards', | |
1032 ); | |
1033 | |
1034 if (isset($_POST['sa']) && $_POST['sa'] == 'ignoreboards' && empty($_POST['ignore_brd'])) | |
1035 $_POST['ignore_brd'] = array(); | |
1036 | |
1037 unset($_POST['ignore_boards']); // Whatever it is set to is a dirty fithy thing. Kinda like our minds. | |
1038 if (isset($_POST['ignore_brd'])) | |
1039 { | |
1040 if (!is_array($_POST['ignore_brd'])) | |
1041 $_POST['ignore_brd'] = array ($_POST['ignore_brd']); | |
1042 | |
1043 foreach ($_POST['ignore_brd'] as $k => $d) | |
1044 { | |
1045 $d = (int) $d; | |
1046 if ($d != 0) | |
1047 $_POST['ignore_brd'][$k] = $d; | |
1048 else | |
1049 unset($_POST['ignore_brd'][$k]); | |
1050 } | |
1051 $_POST['ignore_boards'] = implode(',', $_POST['ignore_brd']); | |
1052 unset($_POST['ignore_brd']); | |
1053 | |
1054 } | |
1055 | |
1056 // Here's where we sort out all the 'other' values... | |
1057 if ($changeOther) | |
1058 { | |
1059 makeThemeChanges($memID, isset($_POST['id_theme']) ? (int) $_POST['id_theme'] : $old_profile['id_theme']); | |
1060 //makeAvatarChanges($memID, $post_errors); | |
1061 makeNotificationChanges($memID); | |
1062 if (!empty($_REQUEST['sa'])) | |
1063 makeCustomFieldChanges($memID, $_REQUEST['sa'], false); | |
1064 | |
1065 foreach ($profile_bools as $var) | |
1066 if (isset($_POST[$var])) | |
1067 $profile_vars[$var] = empty($_POST[$var]) ? '0' : '1'; | |
1068 foreach ($profile_ints as $var) | |
1069 if (isset($_POST[$var])) | |
1070 $profile_vars[$var] = $_POST[$var] != '' ? (int) $_POST[$var] : ''; | |
1071 foreach ($profile_floats as $var) | |
1072 if (isset($_POST[$var])) | |
1073 $profile_vars[$var] = (float) $_POST[$var]; | |
1074 foreach ($profile_strings as $var) | |
1075 if (isset($_POST[$var])) | |
1076 $profile_vars[$var] = $_POST[$var]; | |
1077 } | |
1078 } | |
1079 | |
1080 // Make any theme changes that are sent with the profile.. | |
1081 function makeThemeChanges($memID, $id_theme) | |
1082 { | |
1083 global $modSettings, $smcFunc, $context; | |
1084 | |
1085 $reservedVars = array( | |
1086 'actual_theme_url', | |
1087 'actual_images_url', | |
1088 'base_theme_dir', | |
1089 'base_theme_url', | |
1090 'default_images_url', | |
1091 'default_theme_dir', | |
1092 'default_theme_url', | |
1093 'default_template', | |
1094 'images_url', | |
1095 'number_recent_posts', | |
1096 'smiley_sets_default', | |
1097 'theme_dir', | |
1098 'theme_id', | |
1099 'theme_layers', | |
1100 'theme_templates', | |
1101 'theme_url', | |
1102 ); | |
1103 | |
1104 // Can't change reserved vars. | |
1105 if ((isset($_POST['options']) && array_intersect($_POST['options'], $reservedVars) != array()) || (isset($_POST['default_options']) && array_intersect($_POST['default_options'], $reservedVars) != array())) | |
1106 fatal_lang_error('no_access', false); | |
1107 | |
1108 // Don't allow any overriding of custom fields with default or non-default options. | |
1109 $request = $smcFunc['db_query']('', ' | |
1110 SELECT col_name | |
1111 FROM {db_prefix}custom_fields | |
1112 WHERE active = {int:is_active}', | |
1113 array( | |
1114 'is_active' => 1, | |
1115 ) | |
1116 ); | |
1117 $custom_fields = array(); | |
1118 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
1119 $custom_fields[] = $row['col_name']; | |
1120 $smcFunc['db_free_result']($request); | |
1121 | |
1122 // These are the theme changes... | |
1123 $themeSetArray = array(); | |
1124 if (isset($_POST['options']) && is_array($_POST['options'])) | |
1125 { | |
1126 foreach ($_POST['options'] as $opt => $val) | |
1127 { | |
1128 if (in_array($opt, $custom_fields)) | |
1129 continue; | |
1130 | |
1131 // These need to be controlled. | |
1132 if ($opt == 'topics_per_page' || $opt == 'messages_per_page') | |
1133 $val = max(0, min($val, 50)); | |
1134 | |
1135 $themeSetArray[] = array($memID, $id_theme, $opt, is_array($val) ? implode(',', $val) : $val); | |
1136 } | |
1137 } | |
1138 | |
1139 $erase_options = array(); | |
1140 if (isset($_POST['default_options']) && is_array($_POST['default_options'])) | |
1141 foreach ($_POST['default_options'] as $opt => $val) | |
1142 { | |
1143 if (in_array($opt, $custom_fields)) | |
1144 continue; | |
1145 | |
1146 // These need to be controlled. | |
1147 if ($opt == 'topics_per_page' || $opt == 'messages_per_page') | |
1148 $val = max(0, min($val, 50)); | |
1149 | |
1150 $themeSetArray[] = array($memID, 1, $opt, is_array($val) ? implode(',', $val) : $val); | |
1151 $erase_options[] = $opt; | |
1152 } | |
1153 | |
1154 // If themeSetArray isn't still empty, send it to the database. | |
1155 if (empty($context['password_auth_failed'])) | |
1156 { | |
1157 if (!empty($themeSetArray)) | |
1158 { | |
1159 $smcFunc['db_insert']('replace', | |
1160 '{db_prefix}themes', | |
1161 array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), | |
1162 $themeSetArray, | |
1163 array('id_member', 'id_theme', 'variable') | |
1164 ); | |
1165 } | |
1166 | |
1167 if (!empty($erase_options)) | |
1168 { | |
1169 $smcFunc['db_query']('', ' | |
1170 DELETE FROM {db_prefix}themes | |
1171 WHERE id_theme != {int:id_theme} | |
1172 AND variable IN ({array_string:erase_variables}) | |
1173 AND id_member = {int:id_member}', | |
1174 array( | |
1175 'id_theme' => 1, | |
1176 'id_member' => $memID, | |
1177 'erase_variables' => $erase_options | |
1178 ) | |
1179 ); | |
1180 } | |
1181 | |
1182 $themes = explode(',', $modSettings['knownThemes']); | |
1183 foreach ($themes as $t) | |
1184 cache_put_data('theme_settings-' . $t . ':' . $memID, null, 60); | |
1185 } | |
1186 } | |
1187 | |
1188 // Make any notification changes that need to be made. | |
1189 function makeNotificationChanges($memID) | |
1190 { | |
1191 global $smcFunc; | |
1192 | |
1193 // Update the boards they are being notified on. | |
1194 if (isset($_POST['edit_notify_boards']) && !empty($_POST['notify_boards'])) | |
1195 { | |
1196 // Make sure only integers are deleted. | |
1197 foreach ($_POST['notify_boards'] as $index => $id) | |
1198 $_POST['notify_boards'][$index] = (int) $id; | |
1199 | |
1200 // id_board = 0 is reserved for topic notifications. | |
1201 $_POST['notify_boards'] = array_diff($_POST['notify_boards'], array(0)); | |
1202 | |
1203 $smcFunc['db_query']('', ' | |
1204 DELETE FROM {db_prefix}log_notify | |
1205 WHERE id_board IN ({array_int:board_list}) | |
1206 AND id_member = {int:selected_member}', | |
1207 array( | |
1208 'board_list' => $_POST['notify_boards'], | |
1209 'selected_member' => $memID, | |
1210 ) | |
1211 ); | |
1212 } | |
1213 | |
1214 // We are editing topic notifications...... | |
1215 elseif (isset($_POST['edit_notify_topics']) && !empty($_POST['notify_topics'])) | |
1216 { | |
1217 foreach ($_POST['notify_topics'] as $index => $id) | |
1218 $_POST['notify_topics'][$index] = (int) $id; | |
1219 | |
1220 // Make sure there are no zeros left. | |
1221 $_POST['notify_topics'] = array_diff($_POST['notify_topics'], array(0)); | |
1222 | |
1223 $smcFunc['db_query']('', ' | |
1224 DELETE FROM {db_prefix}log_notify | |
1225 WHERE id_topic IN ({array_int:topic_list}) | |
1226 AND id_member = {int:selected_member}', | |
1227 array( | |
1228 'topic_list' => $_POST['notify_topics'], | |
1229 'selected_member' => $memID, | |
1230 ) | |
1231 ); | |
1232 } | |
1233 } | |
1234 | |
1235 // Save any changes to the custom profile fields... | |
1236 function makeCustomFieldChanges($memID, $area, $sanitize = true) | |
1237 { | |
1238 global $context, $smcFunc, $user_profile, $user_info, $modSettings; | |
1239 | |
1240 if ($sanitize && isset($_POST['customfield'])) | |
1241 $_POST['customfield'] = htmlspecialchars__recursive($_POST['customfield']); | |
1242 | |
1243 $where = $area == 'register' ? 'show_reg != 0' : 'show_profile = {string:area}'; | |
1244 | |
1245 // Load the fields we are saving too - make sure we save valid data (etc). | |
1246 $request = $smcFunc['db_query']('', ' | |
1247 SELECT col_name, field_name, field_desc, field_type, field_length, field_options, default_value, show_reg, mask, private | |
1248 FROM {db_prefix}custom_fields | |
1249 WHERE ' . $where . ' | |
1250 AND active = {int:is_active}', | |
1251 array( | |
1252 'is_active' => 1, | |
1253 'area' => $area, | |
1254 ) | |
1255 ); | |
1256 $changes = array(); | |
1257 $log_changes = array(); | |
1258 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
1259 { | |
1260 /* This means don't save if: | |
1261 - The user is NOT an admin. | |
1262 - The data is not freely viewable and editable by users. | |
1263 - The data is not invisible to users but editable by the owner (or if it is the user is not the owner) | |
1264 - The area isn't registration, and if it is that the field is not suppossed to be shown there. | |
1265 */ | |
1266 if ($row['private'] != 0 && !allowedTo('admin_forum') && ($memID != $user_info['id'] || $row['private'] != 2) && ($area != 'register' || $row['show_reg'] == 0)) | |
1267 continue; | |
1268 | |
1269 // Validate the user data. | |
1270 if ($row['field_type'] == 'check') | |
1271 $value = isset($_POST['customfield'][$row['col_name']]) ? 1 : 0; | |
1272 elseif ($row['field_type'] == 'select' || $row['field_type'] == 'radio') | |
1273 { | |
1274 $value = $row['default_value']; | |
1275 foreach (explode(',', $row['field_options']) as $k => $v) | |
1276 if (isset($_POST['customfield'][$row['col_name']]) && $_POST['customfield'][$row['col_name']] == $k) | |
1277 $value = $v; | |
1278 } | |
1279 // Otherwise some form of text! | |
1280 else | |
1281 { | |
1282 $value = isset($_POST['customfield'][$row['col_name']]) ? $_POST['customfield'][$row['col_name']] : ''; | |
1283 if ($row['field_length']) | |
1284 $value = $smcFunc['substr']($value, 0, $row['field_length']); | |
1285 | |
1286 // Any masks? | |
1287 if ($row['field_type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none') | |
1288 { | |
1289 //!!! We never error on this - just ignore it at the moment... | |
1290 if ($row['mask'] == 'email' && (preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $value) === 0 || strlen($value) > 255)) | |
1291 $value = ''; | |
1292 elseif ($row['mask'] == 'number') | |
1293 { | |
1294 $value = (int) $value; | |
1295 } | |
1296 elseif (substr($row['mask'], 0, 5) == 'regex' && preg_match(substr($row['mask'], 5), $value) === 0) | |
1297 $value = ''; | |
1298 } | |
1299 } | |
1300 | |
1301 // Did it change? | |
1302 if (!isset($user_profile[$memID]['options'][$row['col_name']]) || $user_profile[$memID]['options'][$row['col_name']] != $value) | |
1303 { | |
1304 $log_changes[] = array( | |
1305 'action' => 'customfield_' . $row['col_name'], | |
1306 'id_log' => 2, | |
1307 'log_time' => time(), | |
1308 'id_member' => $memID, | |
1309 'ip' => $user_info['ip'], | |
1310 'extra' => serialize(array('previous' => !empty($user_profile[$memID]['options'][$row['col_name']]) ? $user_profile[$memID]['options'][$row['col_name']] : '', 'new' => $value, 'applicator' => $user_info['id'])), | |
1311 ); | |
1312 $changes[] = array(1, $row['col_name'], $value, $memID); | |
1313 $user_profile[$memID]['options'][$row['col_name']] = $value; | |
1314 } | |
1315 } | |
1316 $smcFunc['db_free_result']($request); | |
1317 | |
1318 // Make those changes! | |
1319 if (!empty($changes) && empty($context['password_auth_failed'])) | |
1320 { | |
1321 $smcFunc['db_insert']('replace', | |
1322 '{db_prefix}themes', | |
1323 array('id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534', 'id_member' => 'int'), | |
1324 $changes, | |
1325 array('id_theme', 'variable', 'id_member') | |
1326 ); | |
1327 if (!empty($log_changes) && !empty($modSettings['modlog_enabled'])) | |
1328 $smcFunc['db_insert']('', | |
1329 '{db_prefix}log_actions', | |
1330 array( | |
1331 'action' => 'string', 'id_log' => 'int', 'log_time' => 'int', 'id_member' => 'int', 'ip' => 'string-16', | |
1332 'extra' => 'string-65534', | |
1333 ), | |
1334 $log_changes, | |
1335 array('id_action') | |
1336 ); | |
1337 } | |
1338 } | |
1339 | |
1340 // Show all the users buddies, as well as a add/delete interface. | |
1341 function editBuddyIgnoreLists($memID) | |
1342 { | |
1343 global $sourcedir, $context, $txt, $scripturl, $modSettings, $user_profile; | |
1344 | |
1345 // Do a quick check to ensure people aren't getting here illegally! | |
1346 if (!$context['user']['is_owner'] || empty($modSettings['enable_buddylist'])) | |
1347 fatal_lang_error('no_access', false); | |
1348 | |
1349 // Can we email the user direct? | |
1350 $context['can_moderate_forum'] = allowedTo('moderate_forum'); | |
1351 | |
1352 $subActions = array( | |
1353 'buddies' => array('editBuddies', $txt['editBuddies']), | |
1354 'ignore' => array('editIgnoreList', $txt['editIgnoreList']), | |
1355 ); | |
1356 | |
1357 $context['list_area'] = isset($_GET['sa']) && isset($subActions[$_GET['sa']]) ? $_GET['sa'] : 'buddies'; | |
1358 | |
1359 // Create the tabs for the template. | |
1360 $context[$context['profile_menu_name']]['tab_data'] = array( | |
1361 'title' => $txt['editBuddyIgnoreLists'], | |
1362 'description' => $txt['buddy_ignore_desc'], | |
1363 'icon' => 'profile_sm.gif', | |
1364 'tabs' => array( | |
1365 'buddies' => array(), | |
1366 'ignore' => array(), | |
1367 ), | |
1368 ); | |
1369 | |
1370 // Pass on to the actual function. | |
1371 $context['sub_template'] = $subActions[$context['list_area']][0]; | |
1372 $subActions[$context['list_area']][0]($memID); | |
1373 } | |
1374 | |
1375 // Show all the users buddies, as well as a add/delete interface. | |
1376 function editBuddies($memID) | |
1377 { | |
1378 global $txt, $scripturl, $modSettings; | |
1379 global $context, $user_profile, $memberContext, $smcFunc; | |
1380 | |
1381 // For making changes! | |
1382 $buddiesArray = explode(',', $user_profile[$memID]['buddy_list']); | |
1383 foreach ($buddiesArray as $k => $dummy) | |
1384 if ($dummy == '') | |
1385 unset($buddiesArray[$k]); | |
1386 | |
1387 // Removing a buddy? | |
1388 if (isset($_GET['remove'])) | |
1389 { | |
1390 checkSession('get'); | |
1391 | |
1392 // Heh, I'm lazy, do it the easy way... | |
1393 foreach ($buddiesArray as $key => $buddy) | |
1394 if ($buddy == (int) $_GET['remove']) | |
1395 unset($buddiesArray[$key]); | |
1396 | |
1397 // Make the changes. | |
1398 $user_profile[$memID]['buddy_list'] = implode(',', $buddiesArray); | |
1399 updateMemberData($memID, array('buddy_list' => $user_profile[$memID]['buddy_list'])); | |
1400 | |
1401 // Redirect off the page because we don't like all this ugly query stuff to stick in the history. | |
1402 redirectexit('action=profile;area=lists;sa=buddies;u=' . $memID); | |
1403 } | |
1404 elseif (isset($_POST['new_buddy'])) | |
1405 { | |
1406 // Prepare the string for extraction... | |
1407 $_POST['new_buddy'] = strtr($smcFunc['htmlspecialchars']($_POST['new_buddy'], ENT_QUOTES), array('"' => '"')); | |
1408 preg_match_all('~"([^"]+)"~', $_POST['new_buddy'], $matches); | |
1409 $new_buddies = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_POST['new_buddy'])))); | |
1410 | |
1411 foreach ($new_buddies as $k => $dummy) | |
1412 { | |
1413 $new_buddies[$k] = strtr(trim($new_buddies[$k]), array('\'' => ''')); | |
1414 | |
1415 if (strlen($new_buddies[$k]) == 0 || in_array($new_buddies[$k], array($user_profile[$memID]['member_name'], $user_profile[$memID]['real_name']))) | |
1416 unset($new_buddies[$k]); | |
1417 } | |
1418 | |
1419 if (!empty($new_buddies)) | |
1420 { | |
1421 // Now find out the id_member of the buddy. | |
1422 $request = $smcFunc['db_query']('', ' | |
1423 SELECT id_member | |
1424 FROM {db_prefix}members | |
1425 WHERE member_name IN ({array_string:new_buddies}) OR real_name IN ({array_string:new_buddies}) | |
1426 LIMIT {int:count_new_buddies}', | |
1427 array( | |
1428 'new_buddies' => $new_buddies, | |
1429 'count_new_buddies' => count($new_buddies), | |
1430 ) | |
1431 ); | |
1432 | |
1433 // Add the new member to the buddies array. | |
1434 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
1435 $buddiesArray[] = (int) $row['id_member']; | |
1436 $smcFunc['db_free_result']($request); | |
1437 | |
1438 // Now update the current users buddy list. | |
1439 $user_profile[$memID]['buddy_list'] = implode(',', $buddiesArray); | |
1440 updateMemberData($memID, array('buddy_list' => $user_profile[$memID]['buddy_list'])); | |
1441 } | |
1442 | |
1443 // Back to the buddy list! | |
1444 redirectexit('action=profile;area=lists;sa=buddies;u=' . $memID); | |
1445 } | |
1446 | |
1447 // Get all the users "buddies"... | |
1448 $buddies = array(); | |
1449 | |
1450 if (!empty($buddiesArray)) | |
1451 { | |
1452 $result = $smcFunc['db_query']('', ' | |
1453 SELECT id_member | |
1454 FROM {db_prefix}members | |
1455 WHERE id_member IN ({array_int:buddy_list}) | |
1456 ORDER BY real_name | |
1457 LIMIT {int:buddy_list_count}', | |
1458 array( | |
1459 'buddy_list' => $buddiesArray, | |
1460 'buddy_list_count' => substr_count($user_profile[$memID]['buddy_list'], ',') + 1, | |
1461 ) | |
1462 ); | |
1463 while ($row = $smcFunc['db_fetch_assoc']($result)) | |
1464 $buddies[] = $row['id_member']; | |
1465 $smcFunc['db_free_result']($result); | |
1466 } | |
1467 | |
1468 $context['buddy_count'] = count($buddies); | |
1469 | |
1470 // Load all the members up. | |
1471 loadMemberData($buddies, false, 'profile'); | |
1472 | |
1473 // Setup the context for each buddy. | |
1474 $context['buddies'] = array(); | |
1475 foreach ($buddies as $buddy) | |
1476 { | |
1477 loadMemberContext($buddy); | |
1478 $context['buddies'][$buddy] = $memberContext[$buddy]; | |
1479 } | |
1480 } | |
1481 | |
1482 // Allows the user to view their ignore list, as well as the option to manage members on it. | |
1483 function editIgnoreList($memID) | |
1484 { | |
1485 global $txt, $scripturl, $modSettings; | |
1486 global $context, $user_profile, $memberContext, $smcFunc; | |
1487 | |
1488 // For making changes! | |
1489 $ignoreArray = explode(',', $user_profile[$memID]['pm_ignore_list']); | |
1490 foreach ($ignoreArray as $k => $dummy) | |
1491 if ($dummy == '') | |
1492 unset($ignoreArray[$k]); | |
1493 | |
1494 // Removing a member from the ignore list? | |
1495 if (isset($_GET['remove'])) | |
1496 { | |
1497 checkSession('get'); | |
1498 | |
1499 // Heh, I'm lazy, do it the easy way... | |
1500 foreach ($ignoreArray as $key => $id_remove) | |
1501 if ($id_remove == (int) $_GET['remove']) | |
1502 unset($ignoreArray[$key]); | |
1503 | |
1504 // Make the changes. | |
1505 $user_profile[$memID]['pm_ignore_list'] = implode(',', $ignoreArray); | |
1506 updateMemberData($memID, array('pm_ignore_list' => $user_profile[$memID]['pm_ignore_list'])); | |
1507 | |
1508 // Redirect off the page because we don't like all this ugly query stuff to stick in the history. | |
1509 redirectexit('action=profile;area=lists;sa=ignore;u=' . $memID); | |
1510 } | |
1511 elseif (isset($_POST['new_ignore'])) | |
1512 { | |
1513 // Prepare the string for extraction... | |
1514 $_POST['new_ignore'] = strtr($smcFunc['htmlspecialchars']($_POST['new_ignore'], ENT_QUOTES), array('"' => '"')); | |
1515 preg_match_all('~"([^"]+)"~', $_POST['new_ignore'], $matches); | |
1516 $new_entries = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_POST['new_ignore'])))); | |
1517 | |
1518 foreach ($new_entries as $k => $dummy) | |
1519 { | |
1520 $new_entries[$k] = strtr(trim($new_entries[$k]), array('\'' => ''')); | |
1521 | |
1522 if (strlen($new_entries[$k]) == 0 || in_array($new_entries[$k], array($user_profile[$memID]['member_name'], $user_profile[$memID]['real_name']))) | |
1523 unset($new_entries[$k]); | |
1524 } | |
1525 | |
1526 if (!empty($new_entries)) | |
1527 { | |
1528 // Now find out the id_member for the members in question. | |
1529 $request = $smcFunc['db_query']('', ' | |
1530 SELECT id_member | |
1531 FROM {db_prefix}members | |
1532 WHERE member_name IN ({array_string:new_entries}) OR real_name IN ({array_string:new_entries}) | |
1533 LIMIT {int:count_new_entries}', | |
1534 array( | |
1535 'new_entries' => $new_entries, | |
1536 'count_new_entries' => count($new_entries), | |
1537 ) | |
1538 ); | |
1539 | |
1540 // Add the new member to the buddies array. | |
1541 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
1542 $ignoreArray[] = (int) $row['id_member']; | |
1543 $smcFunc['db_free_result']($request); | |
1544 | |
1545 // Now update the current users buddy list. | |
1546 $user_profile[$memID]['pm_ignore_list'] = implode(',', $ignoreArray); | |
1547 updateMemberData($memID, array('pm_ignore_list' => $user_profile[$memID]['pm_ignore_list'])); | |
1548 } | |
1549 | |
1550 // Back to the list of pityful people! | |
1551 redirectexit('action=profile;area=lists;sa=ignore;u=' . $memID); | |
1552 } | |
1553 | |
1554 // Initialise the list of members we're ignoring. | |
1555 $ignored = array(); | |
1556 | |
1557 if (!empty($ignoreArray)) | |
1558 { | |
1559 $result = $smcFunc['db_query']('', ' | |
1560 SELECT id_member | |
1561 FROM {db_prefix}members | |
1562 WHERE id_member IN ({array_int:ignore_list}) | |
1563 ORDER BY real_name | |
1564 LIMIT {int:ignore_list_count}', | |
1565 array( | |
1566 'ignore_list' => $ignoreArray, | |
1567 'ignore_list_count' => substr_count($user_profile[$memID]['pm_ignore_list'], ',') + 1, | |
1568 ) | |
1569 ); | |
1570 while ($row = $smcFunc['db_fetch_assoc']($result)) | |
1571 $ignored[] = $row['id_member']; | |
1572 $smcFunc['db_free_result']($result); | |
1573 } | |
1574 | |
1575 $context['ignore_count'] = count($ignored); | |
1576 | |
1577 // Load all the members up. | |
1578 loadMemberData($ignored, false, 'profile'); | |
1579 | |
1580 // Setup the context for each buddy. | |
1581 $context['ignore_list'] = array(); | |
1582 foreach ($ignored as $ignore_member) | |
1583 { | |
1584 loadMemberContext($ignore_member); | |
1585 $context['ignore_list'][$ignore_member] = $memberContext[$ignore_member]; | |
1586 } | |
1587 } | |
1588 | |
1589 function account($memID) | |
1590 { | |
1591 global $context, $txt; | |
1592 | |
1593 loadThemeOptions($memID); | |
1594 if (allowedTo(array('profile_identity_own', 'profile_identity_any'))) | |
1595 loadCustomFields($memID, 'account'); | |
1596 | |
1597 $context['sub_template'] = 'edit_options'; | |
1598 $context['page_desc'] = $txt['account_info']; | |
1599 | |
1600 setupProfileContext( | |
1601 array( | |
1602 'member_name', 'real_name', 'date_registered', 'posts', 'lngfile', 'hr', | |
1603 'id_group', 'hr', | |
1604 'email_address', 'hide_email', 'show_online', 'hr', | |
1605 'passwrd1', 'passwrd2', 'hr', | |
1606 'secret_question', 'secret_answer', | |
1607 ) | |
1608 ); | |
1609 } | |
1610 | |
1611 function forumProfile($memID) | |
1612 { | |
1613 global $context, $user_profile, $user_info, $txt, $modSettings; | |
1614 | |
1615 loadThemeOptions($memID); | |
1616 if (allowedTo(array('profile_extra_own', 'profile_extra_any'))) | |
1617 loadCustomFields($memID, 'forumprofile'); | |
1618 | |
1619 $context['sub_template'] = 'edit_options'; | |
1620 $context['page_desc'] = $txt['forumProfile_info']; | |
1621 | |
1622 setupProfileContext( | |
1623 array( | |
1624 'avatar_choice', 'hr', 'personal_text', 'hr', | |
1625 'bday1', 'location', 'gender', 'hr', | |
1626 'icq', 'aim', 'msn', 'yim', 'hr', | |
1627 'usertitle', 'signature', 'hr', | |
1628 'karma_good', 'hr', | |
1629 'website_title', 'website_url', | |
1630 ) | |
1631 ); | |
1632 } | |
1633 | |
1634 // Allow the edit of *someone elses* personal message settings. | |
1635 function pmprefs($memID) | |
1636 { | |
1637 global $sourcedir, $context, $txt, $scripturl; | |
1638 | |
1639 loadThemeOptions($memID); | |
1640 loadCustomFields($memID, 'pmprefs'); | |
1641 | |
1642 $context['sub_template'] = 'edit_options'; | |
1643 $context['page_desc'] = $txt['pm_settings_desc']; | |
1644 | |
1645 setupProfileContext( | |
1646 array( | |
1647 'pm_prefs', | |
1648 ) | |
1649 ); | |
1650 } | |
1651 | |
1652 // Recursive function to retrieve avatar files | |
1653 function getAvatars($directory, $level) | |
1654 { | |
1655 global $context, $txt, $modSettings; | |
1656 | |
1657 $result = array(); | |
1658 | |
1659 // Open the directory.. | |
1660 $dir = dir($modSettings['avatar_directory'] . (!empty($directory) ? '/' : '') . $directory); | |
1661 $dirs = array(); | |
1662 $files = array(); | |
1663 | |
1664 if (!$dir) | |
1665 return array(); | |
1666 | |
1667 while ($line = $dir->read()) | |
1668 { | |
1669 if (in_array($line, array('.', '..', 'blank.gif', 'index.php'))) | |
1670 continue; | |
1671 | |
1672 if (is_dir($modSettings['avatar_directory'] . '/' . $directory . (!empty($directory) ? '/' : '') . $line)) | |
1673 $dirs[] = $line; | |
1674 else | |
1675 $files[] = $line; | |
1676 } | |
1677 $dir->close(); | |
1678 | |
1679 // Sort the results... | |
1680 natcasesort($dirs); | |
1681 natcasesort($files); | |
1682 | |
1683 if ($level == 0) | |
1684 { | |
1685 $result[] = array( | |
1686 'filename' => 'blank.gif', | |
1687 'checked' => in_array($context['member']['avatar']['server_pic'], array('', 'blank.gif')), | |
1688 'name' => $txt['no_pic'], | |
1689 'is_dir' => false | |
1690 ); | |
1691 } | |
1692 | |
1693 foreach ($dirs as $line) | |
1694 { | |
1695 $tmp = getAvatars($directory . (!empty($directory) ? '/' : '') . $line, $level + 1); | |
1696 if (!empty($tmp)) | |
1697 $result[] = array( | |
1698 'filename' => htmlspecialchars($line), | |
1699 'checked' => strpos($context['member']['avatar']['server_pic'], $line . '/') !== false, | |
1700 'name' => '[' . htmlspecialchars(str_replace('_', ' ', $line)) . ']', | |
1701 'is_dir' => true, | |
1702 'files' => $tmp | |
1703 ); | |
1704 unset($tmp); | |
1705 } | |
1706 | |
1707 foreach ($files as $line) | |
1708 { | |
1709 $filename = substr($line, 0, (strlen($line) - strlen(strrchr($line, '.')))); | |
1710 $extension = substr(strrchr($line, '.'), 1); | |
1711 | |
1712 // Make sure it is an image. | |
1713 if (strcasecmp($extension, 'gif') != 0 && strcasecmp($extension, 'jpg') != 0 && strcasecmp($extension, 'jpeg') != 0 && strcasecmp($extension, 'png') != 0 && strcasecmp($extension, 'bmp') != 0) | |
1714 continue; | |
1715 | |
1716 $result[] = array( | |
1717 'filename' => htmlspecialchars($line), | |
1718 'checked' => $line == $context['member']['avatar']['server_pic'], | |
1719 'name' => htmlspecialchars(str_replace('_', ' ', $filename)), | |
1720 'is_dir' => false | |
1721 ); | |
1722 if ($level == 1) | |
1723 $context['avatar_list'][] = $directory . '/' . $line; | |
1724 } | |
1725 | |
1726 return $result; | |
1727 } | |
1728 | |
1729 function theme($memID) | |
1730 { | |
1731 global $txt, $context, $user_profile, $modSettings, $settings, $user_info, $smcFunc; | |
1732 | |
1733 loadThemeOptions($memID); | |
1734 if (allowedTo(array('profile_extra_own', 'profile_extra_any'))) | |
1735 loadCustomFields($memID, 'theme'); | |
1736 | |
1737 $context['sub_template'] = 'edit_options'; | |
1738 $context['page_desc'] = $txt['theme_info']; | |
1739 | |
1740 setupProfileContext( | |
1741 array( | |
1742 'id_theme', 'smiley_set', 'hr', | |
1743 'time_format', 'time_offset', 'hr', | |
1744 'theme_settings', | |
1745 ) | |
1746 ); | |
1747 } | |
1748 | |
1749 // Changing authentication method? Only appropriate for people using OpenID. | |
1750 function authentication($memID, $saving = false) | |
1751 { | |
1752 global $context, $cur_profile, $sourcedir, $txt, $post_errors, $modSettings; | |
1753 | |
1754 loadLanguage('Login'); | |
1755 | |
1756 // We are saving? | |
1757 if ($saving) | |
1758 { | |
1759 // Moving to password passed authentication? | |
1760 if ($_POST['authenticate'] == 'passwd') | |
1761 { | |
1762 // Didn't enter anything? | |
1763 if ($_POST['passwrd1'] == '') | |
1764 $post_errors[] = 'no_password'; | |
1765 // Do the two entries for the password even match? | |
1766 elseif (!isset($_POST['passwrd2']) || $_POST['passwrd1'] != $_POST['passwrd2']) | |
1767 $post_errors[] = 'bad_new_password'; | |
1768 // Is it valid? | |
1769 else | |
1770 { | |
1771 require_once($sourcedir . '/Subs-Auth.php'); | |
1772 $passwordErrors = validatePassword($_POST['passwrd1'], $cur_profile['member_name'], array($cur_profile['real_name'], $cur_profile['email_address'])); | |
1773 | |
1774 // Were there errors? | |
1775 if ($passwordErrors != null) | |
1776 $post_errors[] = 'password_' . $passwordErrors; | |
1777 } | |
1778 | |
1779 if (empty($post_errors)) | |
1780 { | |
1781 // Integration? | |
1782 call_integration_hook('integrate_reset_pass', array($cur_profile['member_name'], $cur_profile['member_name'], $_POST['passwrd1'])); | |
1783 | |
1784 // Go then. | |
1785 $passwd = sha1(strtolower($cur_profile['member_name']) . un_htmlspecialchars($_POST['passwrd1'])); | |
1786 | |
1787 // Do the important bits. | |
1788 updateMemberData($memID, array('openid_uri' => '', 'passwd' => $passwd)); | |
1789 if ($context['user']['is_owner']) | |
1790 setLoginCookie(60 * $modSettings['cookieTime'], $memID, sha1(sha1(strtolower($cur_profile['member_name']) . un_htmlspecialchars($_POST['passwrd2'])) . $cur_profile['password_salt'])); | |
1791 | |
1792 redirectexit('action=profile;u=' . $memID); | |
1793 } | |
1794 | |
1795 return true; | |
1796 } | |
1797 // Not right yet! | |
1798 elseif ($_POST['authenticate'] == 'openid' && !empty($_POST['openid_identifier'])) | |
1799 { | |
1800 require_once($sourcedir . '/Subs-OpenID.php'); | |
1801 $_POST['openid_identifier'] = smf_openID_canonize($_POST['openid_identifier']); | |
1802 | |
1803 if (smf_openid_member_exists($_POST['openid_identifier'])) | |
1804 $post_errors[] = 'openid_in_use'; | |
1805 elseif (empty($post_errors)) | |
1806 { | |
1807 // Authenticate using the new OpenID URI first to make sure they didn't make a mistake. | |
1808 if ($context['user']['is_owner']) | |
1809 { | |
1810 $_SESSION['new_openid_uri'] = $_POST['openid_identifier']; | |
1811 | |
1812 smf_openID_validate($_POST['openid_identifier'], false, null, 'change_uri'); | |
1813 } | |
1814 else | |
1815 updateMemberData($memID, array('openid_uri' => $_POST['openid_identifier'])); | |
1816 } | |
1817 } | |
1818 } | |
1819 | |
1820 // Some stuff. | |
1821 $context['member']['openid_uri'] = $cur_profile['openid_uri']; | |
1822 $context['auth_method'] = empty($cur_profile['openid_uri']) ? 'password' : 'openid'; | |
1823 $context['sub_template'] = 'authentication_method'; | |
1824 } | |
1825 | |
1826 // Display the notifications and settings for changes. | |
1827 function notification($memID) | |
1828 { | |
1829 global $txt, $scripturl, $user_profile, $user_info, $context, $modSettings, $smcFunc, $sourcedir, $settings; | |
1830 | |
1831 // Gonna want this for the list. | |
1832 require_once($sourcedir . '/Subs-List.php'); | |
1833 | |
1834 // Fine, start with the board list. | |
1835 $listOptions = array( | |
1836 'id' => 'board_notification_list', | |
1837 'width' => '100%', | |
1838 'no_items_label' => $txt['notifications_boards_none'] . '<br /><br />' . $txt['notifications_boards_howto'], | |
1839 'no_items_align' => 'left', | |
1840 'base_href' => $scripturl . '?action=profile;u=' . $memID . ';area=notification', | |
1841 'default_sort_col' => 'board_name', | |
1842 'get_items' => array( | |
1843 'function' => 'list_getBoardNotifications', | |
1844 'params' => array( | |
1845 $memID, | |
1846 ), | |
1847 ), | |
1848 'columns' => array( | |
1849 'board_name' => array( | |
1850 'header' => array( | |
1851 'value' => $txt['notifications_boards'], | |
1852 'class' => 'lefttext first_th', | |
1853 ), | |
1854 'data' => array( | |
1855 'function' => create_function('$board', ' | |
1856 global $settings, $txt; | |
1857 | |
1858 $link = $board[\'link\']; | |
1859 | |
1860 if ($board[\'new\']) | |
1861 $link .= \' <a href="\' . $board[\'href\'] . \'"><img src="\' . $settings[\'lang_images_url\'] . \'/new.gif" alt="\' . $txt[\'new\'] . \'" /></a>\'; | |
1862 | |
1863 return $link; | |
1864 '), | |
1865 ), | |
1866 'sort' => array( | |
1867 'default' => 'name', | |
1868 'reverse' => 'name DESC', | |
1869 ), | |
1870 ), | |
1871 'delete' => array( | |
1872 'header' => array( | |
1873 'value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />', | |
1874 'style' => 'width: 4%;', | |
1875 ), | |
1876 'data' => array( | |
1877 'sprintf' => array( | |
1878 'format' => '<input type="checkbox" name="notify_boards[]" value="%1$d" class="input_check" />', | |
1879 'params' => array( | |
1880 'id' => false, | |
1881 ), | |
1882 ), | |
1883 'style' => 'text-align: center;', | |
1884 ), | |
1885 ), | |
1886 ), | |
1887 'form' => array( | |
1888 'href' => $scripturl . '?action=profile;area=notification;save', | |
1889 'include_sort' => true, | |
1890 'include_start' => true, | |
1891 'hidden_fields' => array( | |
1892 'u' => $memID, | |
1893 'sa' => $context['menu_item_selected'], | |
1894 $context['session_var'] => $context['session_id'], | |
1895 ), | |
1896 ), | |
1897 'additional_rows' => array( | |
1898 array( | |
1899 'position' => 'bottom_of_list', | |
1900 'value' => '<input type="submit" name="edit_notify_boards" value="' . $txt['notifications_update'] . '" class="button_submit" />', | |
1901 'align' => 'right', | |
1902 ), | |
1903 ), | |
1904 ); | |
1905 | |
1906 // Create the board notification list. | |
1907 createList($listOptions); | |
1908 | |
1909 // Now do the topic notifications. | |
1910 $listOptions = array( | |
1911 'id' => 'topic_notification_list', | |
1912 'width' => '100%', | |
1913 'items_per_page' => $modSettings['defaultMaxMessages'], | |
1914 'no_items_label' => $txt['notifications_topics_none'] . '<br /><br />' . $txt['notifications_topics_howto'], | |
1915 'no_items_align' => 'left', | |
1916 'base_href' => $scripturl . '?action=profile;u=' . $memID . ';area=notification', | |
1917 'default_sort_col' => 'last_post', | |
1918 'get_items' => array( | |
1919 'function' => 'list_getTopicNotifications', | |
1920 'params' => array( | |
1921 $memID, | |
1922 ), | |
1923 ), | |
1924 'get_count' => array( | |
1925 'function' => 'list_getTopicNotificationCount', | |
1926 'params' => array( | |
1927 $memID, | |
1928 ), | |
1929 ), | |
1930 'columns' => array( | |
1931 'subject' => array( | |
1932 'header' => array( | |
1933 'value' => $txt['notifications_topics'], | |
1934 'class' => 'lefttext first_th', | |
1935 ), | |
1936 'data' => array( | |
1937 'function' => create_function('$topic', ' | |
1938 global $settings, $txt; | |
1939 | |
1940 $link = $topic[\'link\']; | |
1941 | |
1942 if ($topic[\'new\']) | |
1943 $link .= \' <a href="\' . $topic[\'new_href\'] . \'"><img src="\' . $settings[\'lang_images_url\'] . \'/new.gif" alt="\' . $txt[\'new\'] . \'" /></a>\'; | |
1944 | |
1945 $link .= \'<br /><span class="smalltext"><em>\' . $txt[\'in\'] . \' \' . $topic[\'board_link\'] . \'</em></span>\'; | |
1946 | |
1947 return $link; | |
1948 '), | |
1949 ), | |
1950 'sort' => array( | |
1951 'default' => 'ms.subject', | |
1952 'reverse' => 'ms.subject DESC', | |
1953 ), | |
1954 ), | |
1955 'started_by' => array( | |
1956 'header' => array( | |
1957 'value' => $txt['started_by'], | |
1958 'class' => 'lefttext', | |
1959 ), | |
1960 'data' => array( | |
1961 'db' => 'poster_link', | |
1962 ), | |
1963 'sort' => array( | |
1964 'default' => 'real_name_col', | |
1965 'reverse' => 'real_name_col DESC', | |
1966 ), | |
1967 ), | |
1968 'last_post' => array( | |
1969 'header' => array( | |
1970 'value' => $txt['last_post'], | |
1971 'class' => 'lefttext', | |
1972 ), | |
1973 'data' => array( | |
1974 'sprintf' => array( | |
1975 'format' => '<span class="smalltext">%1$s<br />' . $txt['by'] . ' %2$s</span>', | |
1976 'params' => array( | |
1977 'updated' => false, | |
1978 'poster_updated_link' => false, | |
1979 ), | |
1980 ), | |
1981 ), | |
1982 'sort' => array( | |
1983 'default' => 'ml.id_msg DESC', | |
1984 'reverse' => 'ml.id_msg', | |
1985 ), | |
1986 ), | |
1987 'delete' => array( | |
1988 'header' => array( | |
1989 'value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />', | |
1990 'style' => 'width: 4%;', | |
1991 ), | |
1992 'data' => array( | |
1993 'sprintf' => array( | |
1994 'format' => '<input type="checkbox" name="notify_topics[]" value="%1$d" class="input_check" />', | |
1995 'params' => array( | |
1996 'id' => false, | |
1997 ), | |
1998 ), | |
1999 'style' => 'text-align: center;', | |
2000 ), | |
2001 ), | |
2002 ), | |
2003 'form' => array( | |
2004 'href' => $scripturl . '?action=profile;area=notification;save', | |
2005 'include_sort' => true, | |
2006 'include_start' => true, | |
2007 'hidden_fields' => array( | |
2008 'u' => $memID, | |
2009 'sa' => $context['menu_item_selected'], | |
2010 $context['session_var'] => $context['session_id'], | |
2011 ), | |
2012 ), | |
2013 'additional_rows' => array( | |
2014 array( | |
2015 'position' => 'bottom_of_list', | |
2016 'value' => '<input type="submit" name="edit_notify_topics" value="' . $txt['notifications_update'] . '" class="button_submit" />', | |
2017 'align' => 'right', | |
2018 ), | |
2019 ), | |
2020 ); | |
2021 | |
2022 // Create the notification list. | |
2023 createList($listOptions); | |
2024 | |
2025 // What options are set? | |
2026 $context['member'] += array( | |
2027 'notify_announcements' => $user_profile[$memID]['notify_announcements'], | |
2028 'notify_send_body' => $user_profile[$memID]['notify_send_body'], | |
2029 'notify_types' => $user_profile[$memID]['notify_types'], | |
2030 'notify_regularity' => $user_profile[$memID]['notify_regularity'], | |
2031 ); | |
2032 | |
2033 loadThemeOptions($memID); | |
2034 } | |
2035 | |
2036 function list_getTopicNotificationCount($memID) | |
2037 { | |
2038 global $smcFunc, $user_info, $context, $modSettings; | |
2039 | |
2040 $request = $smcFunc['db_query']('', ' | |
2041 SELECT COUNT(*) | |
2042 FROM {db_prefix}log_notify AS ln' . (!$modSettings['postmod_active'] && $user_info['query_see_board'] === '1=1' ? '' : ' | |
2043 INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ln.id_topic)') . ($user_info['query_see_board'] === '1=1' ? '' : ' | |
2044 INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)') . ' | |
2045 WHERE ln.id_member = {int:selected_member}' . ($user_info['query_see_board'] === '1=1' ? '' : ' | |
2046 AND {query_see_board}') . ($modSettings['postmod_active'] ? ' | |
2047 AND t.approved = {int:is_approved}' : ''), | |
2048 array( | |
2049 'selected_member' => $memID, | |
2050 'is_approved' => 1, | |
2051 ) | |
2052 ); | |
2053 list ($totalNotifications) = $smcFunc['db_fetch_row']($request); | |
2054 $smcFunc['db_free_result']($request); | |
2055 | |
2056 return $totalNotifications; | |
2057 } | |
2058 | |
2059 function list_getTopicNotifications($start, $items_per_page, $sort, $memID) | |
2060 { | |
2061 global $smcFunc, $txt, $scripturl, $user_info, $context, $modSettings; | |
2062 | |
2063 // All the topics with notification on... | |
2064 $request = $smcFunc['db_query']('', ' | |
2065 SELECT | |
2066 IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from, b.id_board, b.name, | |
2067 t.id_topic, ms.subject, ms.id_member, IFNULL(mem.real_name, ms.poster_name) AS real_name_col, | |
2068 ml.id_msg_modified, ml.poster_time, ml.id_member AS id_member_updated, | |
2069 IFNULL(mem2.real_name, ml.poster_name) AS last_real_name | |
2070 FROM {db_prefix}log_notify AS ln | |
2071 INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ln.id_topic' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ') | |
2072 INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board AND {query_see_board}) | |
2073 INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg) | |
2074 INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) | |
2075 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ms.id_member) | |
2076 LEFT JOIN {db_prefix}members AS mem2 ON (mem2.id_member = ml.id_member) | |
2077 LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member}) | |
2078 LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = b.id_board AND lmr.id_member = {int:current_member}) | |
2079 WHERE ln.id_member = {int:selected_member} | |
2080 ORDER BY {raw:sort} | |
2081 LIMIT {int:offset}, {int:items_per_page}', | |
2082 array( | |
2083 'current_member' => $user_info['id'], | |
2084 'is_approved' => 1, | |
2085 'selected_member' => $memID, | |
2086 'sort' => $sort, | |
2087 'offset' => $start, | |
2088 'items_per_page' => $items_per_page, | |
2089 ) | |
2090 ); | |
2091 $notification_topics = array(); | |
2092 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
2093 { | |
2094 censorText($row['subject']); | |
2095 | |
2096 $notification_topics[] = array( | |
2097 'id' => $row['id_topic'], | |
2098 'poster_link' => empty($row['id_member']) ? $row['real_name_col'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name_col'] . '</a>', | |
2099 'poster_updated_link' => empty($row['id_member_updated']) ? $row['last_real_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_updated'] . '">' . $row['last_real_name'] . '</a>', | |
2100 'subject' => $row['subject'], | |
2101 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', | |
2102 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['subject'] . '</a>', | |
2103 'new' => $row['new_from'] <= $row['id_msg_modified'], | |
2104 'new_from' => $row['new_from'], | |
2105 'updated' => timeformat($row['poster_time']), | |
2106 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new', | |
2107 'new_link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new">' . $row['subject'] . '</a>', | |
2108 'board_link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>', | |
2109 ); | |
2110 } | |
2111 $smcFunc['db_free_result']($request); | |
2112 | |
2113 return $notification_topics; | |
2114 } | |
2115 | |
2116 function list_getBoardNotifications($start, $items_per_page, $sort, $memID) | |
2117 { | |
2118 global $smcFunc, $txt, $scripturl, $user_info; | |
2119 | |
2120 $request = $smcFunc['db_query']('', ' | |
2121 SELECT b.id_board, b.name, IFNULL(lb.id_msg, 0) AS board_read, b.id_msg_updated | |
2122 FROM {db_prefix}log_notify AS ln | |
2123 INNER JOIN {db_prefix}boards AS b ON (b.id_board = ln.id_board) | |
2124 LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = b.id_board AND lb.id_member = {int:current_member}) | |
2125 WHERE ln.id_member = {int:selected_member} | |
2126 AND {query_see_board} | |
2127 ORDER BY ' . $sort, | |
2128 array( | |
2129 'current_member' => $user_info['id'], | |
2130 'selected_member' => $memID, | |
2131 ) | |
2132 ); | |
2133 $notification_boards = array(); | |
2134 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
2135 $notification_boards[] = array( | |
2136 'id' => $row['id_board'], | |
2137 'name' => $row['name'], | |
2138 'href' => $scripturl . '?board=' . $row['id_board'] . '.0', | |
2139 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>', | |
2140 'new' => $row['board_read'] < $row['id_msg_updated'] | |
2141 ); | |
2142 $smcFunc['db_free_result']($request); | |
2143 | |
2144 return $notification_boards; | |
2145 } | |
2146 | |
2147 function loadThemeOptions($memID) | |
2148 { | |
2149 global $context, $options, $cur_profile, $smcFunc; | |
2150 | |
2151 if (isset($_POST['default_options'])) | |
2152 $_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options']; | |
2153 | |
2154 if ($context['user']['is_owner']) | |
2155 { | |
2156 $context['member']['options'] = $options; | |
2157 if (isset($_POST['options']) && is_array($_POST['options'])) | |
2158 foreach ($_POST['options'] as $k => $v) | |
2159 $context['member']['options'][$k] = $v; | |
2160 } | |
2161 else | |
2162 { | |
2163 $request = $smcFunc['db_query']('', ' | |
2164 SELECT id_member, variable, value | |
2165 FROM {db_prefix}themes | |
2166 WHERE id_theme IN (1, {int:member_theme}) | |
2167 AND id_member IN (-1, {int:selected_member})', | |
2168 array( | |
2169 'member_theme' => (int) $cur_profile['id_theme'], | |
2170 'selected_member' => $memID, | |
2171 ) | |
2172 ); | |
2173 $temp = array(); | |
2174 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
2175 { | |
2176 if ($row['id_member'] == -1) | |
2177 { | |
2178 $temp[$row['variable']] = $row['value']; | |
2179 continue; | |
2180 } | |
2181 | |
2182 if (isset($_POST['options'][$row['variable']])) | |
2183 $row['value'] = $_POST['options'][$row['variable']]; | |
2184 $context['member']['options'][$row['variable']] = $row['value']; | |
2185 } | |
2186 $smcFunc['db_free_result']($request); | |
2187 | |
2188 // Load up the default theme options for any missing. | |
2189 foreach ($temp as $k => $v) | |
2190 { | |
2191 if (!isset($context['member']['options'][$k])) | |
2192 $context['member']['options'][$k] = $v; | |
2193 } | |
2194 } | |
2195 } | |
2196 | |
2197 function ignoreboards($memID) | |
2198 { | |
2199 global $txt, $user_info, $context, $modSettings, $smcFunc, $cur_profile; | |
2200 | |
2201 // Have the admins enabled this option? | |
2202 if (empty($modSettings['allow_ignore_boards'])) | |
2203 fatal_lang_error('ignoreboards_disallowed', 'user'); | |
2204 | |
2205 // Find all the boards this user is allowed to see. | |
2206 $request = $smcFunc['db_query']('order_by_board_order', ' | |
2207 SELECT b.id_cat, c.name AS cat_name, b.id_board, b.name, b.child_level, | |
2208 '. (!empty($cur_profile['ignore_boards']) ? 'b.id_board IN ({array_int:ignore_boards})' : '0') . ' AS is_ignored | |
2209 FROM {db_prefix}boards AS b | |
2210 LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) | |
2211 WHERE {query_see_board} | |
2212 AND redirect = {string:empty_string}', | |
2213 array( | |
2214 'ignore_boards' => !empty($cur_profile['ignore_boards']) ? explode(',', $cur_profile['ignore_boards']) : array(), | |
2215 'empty_string' => '', | |
2216 ) | |
2217 ); | |
2218 $context['num_boards'] = $smcFunc['db_num_rows']($request); | |
2219 $context['categories'] = array(); | |
2220 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
2221 { | |
2222 // This category hasn't been set up yet.. | |
2223 if (!isset($context['categories'][$row['id_cat']])) | |
2224 $context['categories'][$row['id_cat']] = array( | |
2225 'id' => $row['id_cat'], | |
2226 'name' => $row['cat_name'], | |
2227 'boards' => array() | |
2228 ); | |
2229 | |
2230 // Set this board up, and let the template know when it's a child. (indent them..) | |
2231 $context['categories'][$row['id_cat']]['boards'][$row['id_board']] = array( | |
2232 'id' => $row['id_board'], | |
2233 'name' => $row['name'], | |
2234 'child_level' => $row['child_level'], | |
2235 'selected' => $row['is_ignored'], | |
2236 ); | |
2237 } | |
2238 $smcFunc['db_free_result']($request); | |
2239 | |
2240 // Now, let's sort the list of categories into the boards for templates that like that. | |
2241 $temp_boards = array(); | |
2242 foreach ($context['categories'] as $category) | |
2243 { | |
2244 // Include a list of boards per category for easy toggling. | |
2245 $context['categories'][$category['id']]['child_ids'] = array_keys($category['boards']); | |
2246 | |
2247 $temp_boards[] = array( | |
2248 'name' => $category['name'], | |
2249 'child_ids' => array_keys($category['boards']) | |
2250 ); | |
2251 $temp_boards = array_merge($temp_boards, array_values($category['boards'])); | |
2252 } | |
2253 | |
2254 $max_boards = ceil(count($temp_boards) / 2); | |
2255 if ($max_boards == 1) | |
2256 $max_boards = 2; | |
2257 | |
2258 // Now, alternate them so they can be shown left and right ;). | |
2259 $context['board_columns'] = array(); | |
2260 for ($i = 0; $i < $max_boards; $i++) | |
2261 { | |
2262 $context['board_columns'][] = $temp_boards[$i]; | |
2263 if (isset($temp_boards[$i + $max_boards])) | |
2264 $context['board_columns'][] = $temp_boards[$i + $max_boards]; | |
2265 else | |
2266 $context['board_columns'][] = array(); | |
2267 } | |
2268 | |
2269 loadThemeOptions($memID); | |
2270 } | |
2271 | |
2272 // Load all the languages for the profile. | |
2273 function profileLoadLanguages() | |
2274 { | |
2275 global $context, $modSettings, $settings, $cur_profile, $language, $smcFunc; | |
2276 | |
2277 $context['profile_languages'] = array(); | |
2278 | |
2279 // Get our languages! | |
2280 getLanguages(true, true); | |
2281 | |
2282 // Setup our languages. | |
2283 foreach ($context['languages'] as $lang) | |
2284 { | |
2285 $context['profile_languages'][$lang['filename']] = strtr($lang['name'], array('-utf8' => '')); | |
2286 } | |
2287 ksort($context['profile_languages']); | |
2288 | |
2289 // Return whether we should proceed with this. | |
2290 return count($context['profile_languages']) > 1 ? true : false; | |
2291 } | |
2292 | |
2293 // Load all the group info for the profile. | |
2294 function profileLoadGroups() | |
2295 { | |
2296 global $cur_profile, $txt, $context, $smcFunc, $user_settings; | |
2297 | |
2298 $context['member_groups'] = array( | |
2299 0 => array( | |
2300 'id' => 0, | |
2301 'name' => $txt['no_primary_membergroup'], | |
2302 'is_primary' => $cur_profile['id_group'] == 0, | |
2303 'can_be_additional' => false, | |
2304 'can_be_primary' => true, | |
2305 ) | |
2306 ); | |
2307 $curGroups = explode(',', $cur_profile['additional_groups']); | |
2308 | |
2309 // Load membergroups, but only those groups the user can assign. | |
2310 $request = $smcFunc['db_query']('', ' | |
2311 SELECT group_name, id_group, hidden | |
2312 FROM {db_prefix}membergroups | |
2313 WHERE id_group != {int:moderator_group} | |
2314 AND min_posts = {int:min_posts}' . (allowedTo('admin_forum') ? '' : ' | |
2315 AND group_type != {int:is_protected}') . ' | |
2316 ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name', | |
2317 array( | |
2318 'moderator_group' => 3, | |
2319 'min_posts' => -1, | |
2320 'is_protected' => 1, | |
2321 'newbie_group' => 4, | |
2322 ) | |
2323 ); | |
2324 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
2325 { | |
2326 // We should skip the administrator group if they don't have the admin_forum permission! | |
2327 if ($row['id_group'] == 1 && !allowedTo('admin_forum')) | |
2328 continue; | |
2329 | |
2330 $context['member_groups'][$row['id_group']] = array( | |
2331 'id' => $row['id_group'], | |
2332 'name' => $row['group_name'], | |
2333 'is_primary' => $cur_profile['id_group'] == $row['id_group'], | |
2334 'is_additional' => in_array($row['id_group'], $curGroups), | |
2335 'can_be_additional' => true, | |
2336 'can_be_primary' => $row['hidden'] != 2, | |
2337 ); | |
2338 } | |
2339 $smcFunc['db_free_result']($request); | |
2340 | |
2341 $context['member']['group_id'] = $user_settings['id_group']; | |
2342 | |
2343 return true; | |
2344 } | |
2345 | |
2346 // Load key signature context data. | |
2347 function profileLoadSignatureData() | |
2348 { | |
2349 global $modSettings, $context, $txt, $cur_profile, $smcFunc; | |
2350 | |
2351 // Signature limits. | |
2352 list ($sig_limits, $sig_bbc) = explode(':', $modSettings['signature_settings']); | |
2353 $sig_limits = explode(',', $sig_limits); | |
2354 | |
2355 $context['signature_enabled'] = isset($sig_limits[0]) ? $sig_limits[0] : 0; | |
2356 $context['signature_limits'] = array( | |
2357 'max_length' => isset($sig_limits[1]) ? $sig_limits[1] : 0, | |
2358 'max_lines' => isset($sig_limits[2]) ? $sig_limits[2] : 0, | |
2359 'max_images' => isset($sig_limits[3]) ? $sig_limits[3] : 0, | |
2360 'max_smileys' => isset($sig_limits[4]) ? $sig_limits[4] : 0, | |
2361 'max_image_width' => isset($sig_limits[5]) ? $sig_limits[5] : 0, | |
2362 'max_image_height' => isset($sig_limits[6]) ? $sig_limits[6] : 0, | |
2363 'max_font_size' => isset($sig_limits[7]) ? $sig_limits[7] : 0, | |
2364 'bbc' => !empty($sig_bbc) ? explode(',', $sig_bbc) : array(), | |
2365 ); | |
2366 // Kept this line in for backwards compatibility! | |
2367 $context['max_signature_length'] = $context['signature_limits']['max_length']; | |
2368 // Warning message for signature image limits? | |
2369 $context['signature_warning'] = ''; | |
2370 if ($context['signature_limits']['max_image_width'] && $context['signature_limits']['max_image_height']) | |
2371 $context['signature_warning'] = sprintf($txt['profile_error_signature_max_image_size'], $context['signature_limits']['max_image_width'], $context['signature_limits']['max_image_height']); | |
2372 elseif ($context['signature_limits']['max_image_width'] || $context['signature_limits']['max_image_height']) | |
2373 $context['signature_warning'] = sprintf($txt['profile_error_signature_max_image_' . ($context['signature_limits']['max_image_width'] ? 'width' : 'height')], $context['signature_limits'][$context['signature_limits']['max_image_width'] ? 'max_image_width' : 'max_image_height']); | |
2374 | |
2375 $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new'); | |
2376 | |
2377 $context['member']['signature'] = empty($cur_profile['signature']) ? '' : str_replace(array('<br />', '<', '>', '"', '\''), array("\n", '<', '>', '"', '''), $cur_profile['signature']); | |
2378 | |
2379 return true; | |
2380 } | |
2381 | |
2382 // Load avatar context data. | |
2383 function profileLoadAvatarData() | |
2384 { | |
2385 global $context, $cur_profile, $modSettings, $scripturl; | |
2386 | |
2387 $context['avatar_url'] = $modSettings['avatar_url']; | |
2388 | |
2389 // Default context. | |
2390 $context['member']['avatar'] += array( | |
2391 'custom' => stristr($cur_profile['avatar'], 'http://') ? $cur_profile['avatar'] : 'http://', | |
2392 'selection' => $cur_profile['avatar'] == '' || stristr($cur_profile['avatar'], 'http://') ? '' : $cur_profile['avatar'], | |
2393 'id_attach' => $cur_profile['id_attach'], | |
2394 'filename' => $cur_profile['filename'], | |
2395 'allow_server_stored' => allowedTo('profile_server_avatar') || (!$context['user']['is_owner'] && allowedTo('profile_extra_any')), | |
2396 'allow_upload' => allowedTo('profile_upload_avatar') || (!$context['user']['is_owner'] && allowedTo('profile_extra_any')), | |
2397 'allow_external' => allowedTo('profile_remote_avatar') || (!$context['user']['is_owner'] && allowedTo('profile_extra_any')), | |
2398 ); | |
2399 | |
2400 if ($cur_profile['avatar'] == '' && $cur_profile['id_attach'] > 0 && $context['member']['avatar']['allow_upload']) | |
2401 { | |
2402 $context['member']['avatar'] += array( | |
2403 'choice' => 'upload', | |
2404 'server_pic' => 'blank.gif', | |
2405 'external' => 'http://' | |
2406 ); | |
2407 $context['member']['avatar']['href'] = empty($cur_profile['attachment_type']) ? $scripturl . '?action=dlattach;attach=' . $cur_profile['id_attach'] . ';type=avatar' : $modSettings['custom_avatar_url'] . '/' . $cur_profile['filename']; | |
2408 } | |
2409 elseif (stristr($cur_profile['avatar'], 'http://') && $context['member']['avatar']['allow_external']) | |
2410 $context['member']['avatar'] += array( | |
2411 'choice' => 'external', | |
2412 'server_pic' => 'blank.gif', | |
2413 'external' => $cur_profile['avatar'] | |
2414 ); | |
2415 elseif ($cur_profile['avatar'] != '' && file_exists($modSettings['avatar_directory'] . '/' . $cur_profile['avatar']) && $context['member']['avatar']['allow_server_stored']) | |
2416 $context['member']['avatar'] += array( | |
2417 'choice' => 'server_stored', | |
2418 'server_pic' => $cur_profile['avatar'] == '' ? 'blank.gif' : $cur_profile['avatar'], | |
2419 'external' => 'http://' | |
2420 ); | |
2421 else | |
2422 $context['member']['avatar'] += array( | |
2423 'choice' => 'none', | |
2424 'server_pic' => 'blank.gif', | |
2425 'external' => 'http://' | |
2426 ); | |
2427 | |
2428 // Get a list of all the avatars. | |
2429 if ($context['member']['avatar']['allow_server_stored']) | |
2430 { | |
2431 $context['avatar_list'] = array(); | |
2432 $context['avatars'] = is_dir($modSettings['avatar_directory']) ? getAvatars('', 0) : array(); | |
2433 } | |
2434 else | |
2435 $context['avatars'] = array(); | |
2436 | |
2437 // Second level selected avatar... | |
2438 $context['avatar_selected'] = substr(strrchr($context['member']['avatar']['server_pic'], '/'), 1); | |
2439 return true; | |
2440 } | |
2441 | |
2442 // Save a members group. | |
2443 function profileSaveGroups(&$value) | |
2444 { | |
2445 global $profile_vars, $old_profile, $context, $smcFunc, $cur_profile; | |
2446 | |
2447 // Do we need to protect some groups? | |
2448 if (!allowedTo('admin_forum')) | |
2449 { | |
2450 $request = $smcFunc['db_query']('', ' | |
2451 SELECT id_group | |
2452 FROM {db_prefix}membergroups | |
2453 WHERE group_type = {int:is_protected}', | |
2454 array( | |
2455 'is_protected' => 1, | |
2456 ) | |
2457 ); | |
2458 $protected_groups = array(1); | |
2459 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
2460 $protected_groups[] = $row['id_group']; | |
2461 $smcFunc['db_free_result']($request); | |
2462 | |
2463 $protected_groups = array_unique($protected_groups); | |
2464 } | |
2465 | |
2466 // The account page allows the change of your id_group - but not to a protected group! | |
2467 if (empty($protected_groups) || count(array_intersect(array((int) $value, $old_profile['id_group']), $protected_groups)) == 0) | |
2468 $value = (int) $value; | |
2469 // ... otherwise it's the old group sir. | |
2470 else | |
2471 $value = $old_profile['id_group']; | |
2472 | |
2473 // Find the additional membergroups (if any) | |
2474 if (isset($_POST['additional_groups']) && is_array($_POST['additional_groups'])) | |
2475 { | |
2476 $additional_groups = array(); | |
2477 foreach ($_POST['additional_groups'] as $group_id) | |
2478 { | |
2479 $group_id = (int) $group_id; | |
2480 if (!empty($group_id) && (empty($protected_groups) || !in_array($group_id, $protected_groups))) | |
2481 $additional_groups[] = $group_id; | |
2482 } | |
2483 | |
2484 // Put the protected groups back in there if you don't have permission to take them away. | |
2485 $old_additional_groups = explode(',', $old_profile['additional_groups']); | |
2486 foreach ($old_additional_groups as $group_id) | |
2487 { | |
2488 if (!empty($protected_groups) && in_array($group_id, $protected_groups)) | |
2489 $additional_groups[] = $group_id; | |
2490 } | |
2491 | |
2492 if (implode(',', $additional_groups) !== $old_profile['additional_groups']) | |
2493 { | |
2494 $profile_vars['additional_groups'] = implode(',', $additional_groups); | |
2495 $cur_profile['additional_groups'] = implode(',', $additional_groups); | |
2496 } | |
2497 } | |
2498 | |
2499 // Too often, people remove delete their own account, or something. | |
2500 if (in_array(1, explode(',', $old_profile['additional_groups'])) || $old_profile['id_group'] == 1) | |
2501 { | |
2502 $stillAdmin = $value == 1 || (isset($additional_groups) && in_array(1, $additional_groups)); | |
2503 | |
2504 // If they would no longer be an admin, look for any other... | |
2505 if (!$stillAdmin) | |
2506 { | |
2507 $request = $smcFunc['db_query']('', ' | |
2508 SELECT id_member | |
2509 FROM {db_prefix}members | |
2510 WHERE (id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0) | |
2511 AND id_member != {int:selected_member} | |
2512 LIMIT 1', | |
2513 array( | |
2514 'admin_group' => 1, | |
2515 'selected_member' => $context['id_member'], | |
2516 ) | |
2517 ); | |
2518 list ($another) = $smcFunc['db_fetch_row']($request); | |
2519 $smcFunc['db_free_result']($request); | |
2520 | |
2521 if (empty($another)) | |
2522 fatal_lang_error('at_least_one_admin', 'critical'); | |
2523 } | |
2524 } | |
2525 | |
2526 // If we are changing group status, update permission cache as necessary. | |
2527 if ($value != $old_profile['id_group'] || isset($profile_vars['additional_groups'])) | |
2528 { | |
2529 if ($context['user']['is_owner']) | |
2530 $_SESSION['mc']['time'] = 0; | |
2531 else | |
2532 updateSettings(array('settings_updated' => time())); | |
2533 } | |
2534 | |
2535 return true; | |
2536 } | |
2537 | |
2538 // The avatar is incredibly complicated, what with the options... and what not. | |
2539 function profileSaveAvatarData(&$value) | |
2540 { | |
2541 global $modSettings, $sourcedir, $smcFunc, $profile_vars, $cur_profile, $context; | |
2542 | |
2543 $memID = $context['id_member']; | |
2544 if (empty($memID) && !empty($context['password_auth_failed'])) | |
2545 return false; | |
2546 | |
2547 require_once($sourcedir . '/ManageAttachments.php'); | |
2548 | |
2549 // We need to know where we're going to be putting it.. | |
2550 if (!empty($modSettings['custom_avatar_enabled'])) | |
2551 { | |
2552 $uploadDir = $modSettings['custom_avatar_dir']; | |
2553 $id_folder = 1; | |
2554 } | |
2555 elseif (!empty($modSettings['currentAttachmentUploadDir'])) | |
2556 { | |
2557 if (!is_array($modSettings['attachmentUploadDir'])) | |
2558 $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); | |
2559 | |
2560 // Just use the current path for temp files. | |
2561 $uploadDir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; | |
2562 $id_folder = $modSettings['currentAttachmentUploadDir']; | |
2563 } | |
2564 else | |
2565 { | |
2566 $uploadDir = $modSettings['attachmentUploadDir']; | |
2567 $id_folder = 1; | |
2568 } | |
2569 | |
2570 $downloadedExternalAvatar = false; | |
2571 if ($value == 'external' && allowedTo('profile_remote_avatar') && strtolower(substr($_POST['userpicpersonal'], 0, 7)) == 'http://' && strlen($_POST['userpicpersonal']) > 7 && !empty($modSettings['avatar_download_external'])) | |
2572 { | |
2573 if (!is_writable($uploadDir)) | |
2574 fatal_lang_error('attachments_no_write', 'critical'); | |
2575 | |
2576 require_once($sourcedir . '/Subs-Package.php'); | |
2577 | |
2578 $url = parse_url($_POST['userpicpersonal']); | |
2579 $contents = fetch_web_data('http://' . $url['host'] . (empty($url['port']) ? '' : ':' . $url['port']) . str_replace(' ', '%20', trim($url['path']))); | |
2580 | |
2581 if ($contents != false && $tmpAvatar = fopen($uploadDir . '/avatar_tmp_' . $memID, 'wb')) | |
2582 { | |
2583 fwrite($tmpAvatar, $contents); | |
2584 fclose($tmpAvatar); | |
2585 | |
2586 $downloadedExternalAvatar = true; | |
2587 $_FILES['attachment']['tmp_name'] = $uploadDir . '/avatar_tmp_' . $memID; | |
2588 } | |
2589 } | |
2590 | |
2591 if ($value == 'none') | |
2592 { | |
2593 $profile_vars['avatar'] = ''; | |
2594 | |
2595 // Reset the attach ID. | |
2596 $cur_profile['id_attach'] = 0; | |
2597 $cur_profile['attachment_type'] = 0; | |
2598 $cur_profile['filename'] = ''; | |
2599 | |
2600 removeAttachments(array('id_member' => $memID)); | |
2601 } | |
2602 elseif ($value == 'server_stored' && allowedTo('profile_server_avatar')) | |
2603 { | |
2604 $profile_vars['avatar'] = strtr(empty($_POST['file']) ? (empty($_POST['cat']) ? '' : $_POST['cat']) : $_POST['file'], array('&' => '&')); | |
2605 $profile_vars['avatar'] = preg_match('~^([\w _!@%*=\-#()\[\]&.,]+/)?[\w _!@%*=\-#()\[\]&.,]+$~', $profile_vars['avatar']) != 0 && preg_match('/\.\./', $profile_vars['avatar']) == 0 && file_exists($modSettings['avatar_directory'] . '/' . $profile_vars['avatar']) ? ($profile_vars['avatar'] == 'blank.gif' ? '' : $profile_vars['avatar']) : ''; | |
2606 | |
2607 // Clear current profile... | |
2608 $cur_profile['id_attach'] = 0; | |
2609 $cur_profile['attachment_type'] = 0; | |
2610 $cur_profile['filename'] = ''; | |
2611 | |
2612 // Get rid of their old avatar. (if uploaded.) | |
2613 removeAttachments(array('id_member' => $memID)); | |
2614 } | |
2615 elseif ($value == 'external' && allowedTo('profile_remote_avatar') && strtolower(substr($_POST['userpicpersonal'], 0, 7)) == 'http://' && empty($modSettings['avatar_download_external'])) | |
2616 { | |
2617 // We need these clean... | |
2618 $cur_profile['id_attach'] = 0; | |
2619 $cur_profile['attachment_type'] = 0; | |
2620 $cur_profile['filename'] = ''; | |
2621 | |
2622 // Remove any attached avatar... | |
2623 removeAttachments(array('id_member' => $memID)); | |
2624 | |
2625 $profile_vars['avatar'] = str_replace('%20', '', preg_replace('~action(?:=|%3d)(?!dlattach)~i', 'action-', $_POST['userpicpersonal'])); | |
2626 | |
2627 if ($profile_vars['avatar'] == 'http://' || $profile_vars['avatar'] == 'http:///') | |
2628 $profile_vars['avatar'] = ''; | |
2629 // Trying to make us do something we'll regret? | |
2630 elseif (substr($profile_vars['avatar'], 0, 7) != 'http://') | |
2631 return 'bad_avatar'; | |
2632 // Should we check dimensions? | |
2633 elseif (!empty($modSettings['avatar_max_height_external']) || !empty($modSettings['avatar_max_width_external'])) | |
2634 { | |
2635 // Now let's validate the avatar. | |
2636 $sizes = url_image_size($profile_vars['avatar']); | |
2637 | |
2638 if (is_array($sizes) && (($sizes[0] > $modSettings['avatar_max_width_external'] && !empty($modSettings['avatar_max_width_external'])) || ($sizes[1] > $modSettings['avatar_max_height_external'] && !empty($modSettings['avatar_max_height_external'])))) | |
2639 { | |
2640 // Houston, we have a problem. The avatar is too large!! | |
2641 if ($modSettings['avatar_action_too_large'] == 'option_refuse') | |
2642 return 'bad_avatar'; | |
2643 elseif ($modSettings['avatar_action_too_large'] == 'option_download_and_resize') | |
2644 { | |
2645 require_once($sourcedir . '/Subs-Graphics.php'); | |
2646 if (downloadAvatar($profile_vars['avatar'], $memID, $modSettings['avatar_max_width_external'], $modSettings['avatar_max_height_external'])) | |
2647 { | |
2648 $profile_vars['avatar'] = ''; | |
2649 $cur_profile['id_attach'] = $modSettings['new_avatar_data']['id']; | |
2650 $cur_profile['filename'] = $modSettings['new_avatar_data']['filename']; | |
2651 $cur_profile['attachment_type'] = $modSettings['new_avatar_data']['type']; | |
2652 } | |
2653 else | |
2654 return 'bad_avatar'; | |
2655 } | |
2656 } | |
2657 } | |
2658 } | |
2659 elseif (($value == 'upload' && allowedTo('profile_upload_avatar')) || $downloadedExternalAvatar) | |
2660 { | |
2661 if ((isset($_FILES['attachment']['name']) && $_FILES['attachment']['name'] != '') || $downloadedExternalAvatar) | |
2662 { | |
2663 // Get the dimensions of the image. | |
2664 if (!$downloadedExternalAvatar) | |
2665 { | |
2666 if (!is_writable($uploadDir)) | |
2667 fatal_lang_error('attachments_no_write', 'critical'); | |
2668 | |
2669 if (!move_uploaded_file($_FILES['attachment']['tmp_name'], $uploadDir . '/avatar_tmp_' . $memID)) | |
2670 fatal_lang_error('attach_timeout', 'critical'); | |
2671 | |
2672 $_FILES['attachment']['tmp_name'] = $uploadDir . '/avatar_tmp_' . $memID; | |
2673 } | |
2674 | |
2675 $sizes = @getimagesize($_FILES['attachment']['tmp_name']); | |
2676 | |
2677 // No size, then it's probably not a valid pic. | |
2678 if ($sizes === false) | |
2679 return 'bad_avatar'; | |
2680 // Check whether the image is too large. | |
2681 elseif ((!empty($modSettings['avatar_max_width_upload']) && $sizes[0] > $modSettings['avatar_max_width_upload']) || (!empty($modSettings['avatar_max_height_upload']) && $sizes[1] > $modSettings['avatar_max_height_upload'])) | |
2682 { | |
2683 if (!empty($modSettings['avatar_resize_upload'])) | |
2684 { | |
2685 // Attempt to chmod it. | |
2686 @chmod($uploadDir . '/avatar_tmp_' . $memID, 0644); | |
2687 | |
2688 require_once($sourcedir . '/Subs-Graphics.php'); | |
2689 if (!downloadAvatar($uploadDir . '/avatar_tmp_' . $memID, $memID, $modSettings['avatar_max_width_upload'], $modSettings['avatar_max_height_upload'])) | |
2690 return 'bad_avatar'; | |
2691 | |
2692 // Reset attachment avatar data. | |
2693 $cur_profile['id_attach'] = $modSettings['new_avatar_data']['id']; | |
2694 $cur_profile['filename'] = $modSettings['new_avatar_data']['filename']; | |
2695 $cur_profile['attachment_type'] = $modSettings['new_avatar_data']['type']; | |
2696 } | |
2697 else | |
2698 return 'bad_avatar'; | |
2699 } | |
2700 elseif (is_array($sizes)) | |
2701 { | |
2702 // Now try to find an infection. | |
2703 require_once($sourcedir . '/Subs-Graphics.php'); | |
2704 if (!checkImageContents($_FILES['attachment']['tmp_name'], !empty($modSettings['avatar_paranoid']))) | |
2705 { | |
2706 // It's bad. Try to re-encode the contents? | |
2707 if (empty($modSettings['avatar_reencode']) || (!reencodeImage($_FILES['attachment']['tmp_name'], $sizes[2]))) | |
2708 return 'bad_avatar'; | |
2709 // We were successful. However, at what price? | |
2710 $sizes = @getimagesize($_FILES['attachment']['tmp_name']); | |
2711 // Hard to believe this would happen, but can you bet? | |
2712 if ($sizes === false) | |
2713 return 'bad_avatar'; | |
2714 } | |
2715 | |
2716 $extensions = array( | |
2717 '1' => 'gif', | |
2718 '2' => 'jpg', | |
2719 '3' => 'png', | |
2720 '6' => 'bmp' | |
2721 ); | |
2722 | |
2723 $extension = isset($extensions[$sizes[2]]) ? $extensions[$sizes[2]] : 'bmp'; | |
2724 $mime_type = 'image/' . ($extension === 'jpg' ? 'jpeg' : ($extension === 'bmp' ? 'x-ms-bmp' : $extension)); | |
2725 $destName = 'avatar_' . $memID . '_' . time() . '.' . $extension; | |
2726 list ($width, $height) = getimagesize($_FILES['attachment']['tmp_name']); | |
2727 $file_hash = empty($modSettings['custom_avatar_enabled']) ? getAttachmentFilename($destName, false, null, true) : ''; | |
2728 | |
2729 // Remove previous attachments this member might have had. | |
2730 removeAttachments(array('id_member' => $memID)); | |
2731 | |
2732 $smcFunc['db_insert']('', | |
2733 '{db_prefix}attachments', | |
2734 array( | |
2735 'id_member' => 'int', 'attachment_type' => 'int', 'filename' => 'string', 'file_hash' => 'string', 'fileext' => 'string', 'size' => 'int', | |
2736 'width' => 'int', 'height' => 'int', 'mime_type' => 'string', 'id_folder' => 'int', | |
2737 ), | |
2738 array( | |
2739 $memID, (empty($modSettings['custom_avatar_enabled']) ? 0 : 1), $destName, $file_hash, $extension, filesize($_FILES['attachment']['tmp_name']), | |
2740 (int) $width, (int) $height, $mime_type, $id_folder, | |
2741 ), | |
2742 array('id_attach') | |
2743 ); | |
2744 | |
2745 $cur_profile['id_attach'] = $smcFunc['db_insert_id']('{db_prefix}attachments', 'id_attach'); | |
2746 $cur_profile['filename'] = $destName; | |
2747 $cur_profile['attachment_type'] = empty($modSettings['custom_avatar_enabled']) ? 0 : 1; | |
2748 | |
2749 $destinationPath = $uploadDir . '/' . (empty($file_hash) ? $destName : $cur_profile['id_attach'] . '_' . $file_hash); | |
2750 if (!rename($_FILES['attachment']['tmp_name'], $destinationPath)) | |
2751 { | |
2752 // I guess a man can try. | |
2753 removeAttachments(array('id_member' => $memID)); | |
2754 fatal_lang_error('attach_timeout', 'critical'); | |
2755 } | |
2756 | |
2757 // Attempt to chmod it. | |
2758 @chmod($uploadDir . '/' . $destinationPath, 0644); | |
2759 } | |
2760 $profile_vars['avatar'] = ''; | |
2761 | |
2762 // Delete any temporary file. | |
2763 if (file_exists($uploadDir . '/avatar_tmp_' . $memID)) | |
2764 @unlink($uploadDir . '/avatar_tmp_' . $memID); | |
2765 } | |
2766 // Selected the upload avatar option and had one already uploaded before or didn't upload one. | |
2767 else | |
2768 $profile_vars['avatar'] = ''; | |
2769 } | |
2770 else | |
2771 $profile_vars['avatar'] = ''; | |
2772 | |
2773 // Setup the profile variables so it shows things right on display! | |
2774 $cur_profile['avatar'] = $profile_vars['avatar']; | |
2775 | |
2776 return false; | |
2777 } | |
2778 | |
2779 // Validate the signature! | |
2780 function profileValidateSignature(&$value) | |
2781 { | |
2782 global $sourcedir, $modSettings, $smcFunc, $txt; | |
2783 | |
2784 require_once($sourcedir . '/Subs-Post.php'); | |
2785 | |
2786 // Admins can do whatever they hell they want! | |
2787 if (!allowedTo('admin_forum')) | |
2788 { | |
2789 // Load all the signature limits. | |
2790 list ($sig_limits, $sig_bbc) = explode(':', $modSettings['signature_settings']); | |
2791 $sig_limits = explode(',', $sig_limits); | |
2792 $disabledTags = !empty($sig_bbc) ? explode(',', $sig_bbc) : array(); | |
2793 | |
2794 $unparsed_signature = strtr(un_htmlspecialchars($value), array("\r" => '', ''' => '\'')); | |
2795 // Too long? | |
2796 if (!empty($sig_limits[1]) && $smcFunc['strlen']($unparsed_signature) > $sig_limits[1]) | |
2797 { | |
2798 $_POST['signature'] = trim(htmlspecialchars($smcFunc['substr']($unparsed_signature, 0, $sig_limits[1]), ENT_QUOTES)); | |
2799 $txt['profile_error_signature_max_length'] = sprintf($txt['profile_error_signature_max_length'], $sig_limits[1]); | |
2800 return 'signature_max_length'; | |
2801 } | |
2802 // Too many lines? | |
2803 if (!empty($sig_limits[2]) && substr_count($unparsed_signature, "\n") >= $sig_limits[2]) | |
2804 { | |
2805 $txt['profile_error_signature_max_lines'] = sprintf($txt['profile_error_signature_max_lines'], $sig_limits[2]); | |
2806 return 'signature_max_lines'; | |
2807 } | |
2808 // Too many images?! | |
2809 if (!empty($sig_limits[3]) && (substr_count(strtolower($unparsed_signature), '[img') + substr_count(strtolower($unparsed_signature), '<img')) > $sig_limits[3]) | |
2810 { | |
2811 $txt['profile_error_signature_max_image_count'] = sprintf($txt['profile_error_signature_max_image_count'], $sig_limits[3]); | |
2812 return 'signature_max_image_count'; | |
2813 } | |
2814 // What about too many smileys! | |
2815 $smiley_parsed = $unparsed_signature; | |
2816 parsesmileys($smiley_parsed); | |
2817 $smiley_count = substr_count(strtolower($smiley_parsed), '<img') - substr_count(strtolower($unparsed_signature), '<img'); | |
2818 if (!empty($sig_limits[4]) && $sig_limits[4] == -1 && $smiley_count > 0) | |
2819 return 'signature_allow_smileys'; | |
2820 elseif (!empty($sig_limits[4]) && $sig_limits[4] > 0 && $smiley_count > $sig_limits[4]) | |
2821 { | |
2822 $txt['profile_error_signature_max_smileys'] = sprintf($txt['profile_error_signature_max_smileys'], $sig_limits[4]); | |
2823 return 'signature_max_smileys'; | |
2824 } | |
2825 // Maybe we are abusing font sizes? | |
2826 if (!empty($sig_limits[7]) && preg_match_all('~\[size=([\d\.]+)?(px|pt|em|x-large|larger)~i', $unparsed_signature, $matches) !== false && isset($matches[2])) | |
2827 { | |
2828 foreach ($matches[1] as $ind => $size) | |
2829 { | |
2830 $limit_broke = 0; | |
2831 // Attempt to allow all sizes of abuse, so to speak. | |
2832 if ($matches[2][$ind] == 'px' && $size > $sig_limits[7]) | |
2833 $limit_broke = $sig_limits[7] . 'px'; | |
2834 elseif ($matches[2][$ind] == 'pt' && $size > ($sig_limits[7] * 0.75)) | |
2835 $limit_broke = ((int) $sig_limits[7] * 0.75) . 'pt'; | |
2836 elseif ($matches[2][$ind] == 'em' && $size > ((float) $sig_limits[7] / 16)) | |
2837 $limit_broke = ((float) $sig_limits[7] / 16) . 'em'; | |
2838 elseif ($matches[2][$ind] != 'px' && $matches[2][$ind] != 'pt' && $matches[2][$ind] != 'em' && $sig_limits[7] < 18) | |
2839 $limit_broke = 'large'; | |
2840 | |
2841 if ($limit_broke) | |
2842 { | |
2843 $txt['profile_error_signature_max_font_size'] = sprintf($txt['profile_error_signature_max_font_size'], $limit_broke); | |
2844 return 'signature_max_font_size'; | |
2845 } | |
2846 } | |
2847 } | |
2848 // The difficult one - image sizes! Don't error on this - just fix it. | |
2849 if ((!empty($sig_limits[5]) || !empty($sig_limits[6]))) | |
2850 { | |
2851 // Get all BBC tags... | |
2852 preg_match_all('~\[img(\s+width=([\d]+))?(\s+height=([\d]+))?(\s+width=([\d]+))?\s*\](?:<br />)*([^<">]+?)(?:<br />)*\[/img\]~i', $unparsed_signature, $matches); | |
2853 // ... and all HTML ones. | |
2854 preg_match_all('~<img\s+src=(?:")?((?:http://|ftp://|https://|ftps://).+?)(?:")?(?:\s+alt=(?:")?(.*?)(?:")?)?(?:\s?/)?>~i', $unparsed_signature, $matches2, PREG_PATTERN_ORDER); | |
2855 // And stick the HTML in the BBC. | |
2856 if (!empty($matches2)) | |
2857 { | |
2858 foreach ($matches2[0] as $ind => $dummy) | |
2859 { | |
2860 $matches[0][] = $matches2[0][$ind]; | |
2861 $matches[1][] = ''; | |
2862 $matches[2][] = ''; | |
2863 $matches[3][] = ''; | |
2864 $matches[4][] = ''; | |
2865 $matches[5][] = ''; | |
2866 $matches[6][] = ''; | |
2867 $matches[7][] = $matches2[1][$ind]; | |
2868 } | |
2869 } | |
2870 | |
2871 $replaces = array(); | |
2872 // Try to find all the images! | |
2873 if (!empty($matches)) | |
2874 { | |
2875 foreach ($matches[0] as $key => $image) | |
2876 { | |
2877 $width = -1; $height = -1; | |
2878 | |
2879 // Does it have predefined restraints? Width first. | |
2880 if ($matches[6][$key]) | |
2881 $matches[2][$key] = $matches[6][$key]; | |
2882 if ($matches[2][$key] && $sig_limits[5] && $matches[2][$key] > $sig_limits[5]) | |
2883 { | |
2884 $width = $sig_limits[5]; | |
2885 $matches[4][$key] = $matches[4][$key] * ($width / $matches[2][$key]); | |
2886 } | |
2887 elseif ($matches[2][$key]) | |
2888 $width = $matches[2][$key]; | |
2889 // ... and height. | |
2890 if ($matches[4][$key] && $sig_limits[6] && $matches[4][$key] > $sig_limits[6]) | |
2891 { | |
2892 $height = $sig_limits[6]; | |
2893 if ($width != -1) | |
2894 $width = $width * ($height / $matches[4][$key]); | |
2895 } | |
2896 elseif ($matches[4][$key]) | |
2897 $height = $matches[4][$key]; | |
2898 | |
2899 // If the dimensions are still not fixed - we need to check the actual image. | |
2900 if (($width == -1 && $sig_limits[5]) || ($height == -1 && $sig_limits[6])) | |
2901 { | |
2902 $sizes = url_image_size($matches[7][$key]); | |
2903 if (is_array($sizes)) | |
2904 { | |
2905 // Too wide? | |
2906 if ($sizes[0] > $sig_limits[5] && $sig_limits[5]) | |
2907 { | |
2908 $width = $sig_limits[5]; | |
2909 $sizes[1] = $sizes[1] * ($width / $sizes[0]); | |
2910 } | |
2911 // Too high? | |
2912 if ($sizes[1] > $sig_limits[6] && $sig_limits[6]) | |
2913 { | |
2914 $height = $sig_limits[6]; | |
2915 if ($width == -1) | |
2916 $width = $sizes[0]; | |
2917 $width = $width * ($height / $sizes[1]); | |
2918 } | |
2919 elseif ($width != -1) | |
2920 $height = $sizes[1]; | |
2921 } | |
2922 } | |
2923 | |
2924 // Did we come up with some changes? If so remake the string. | |
2925 if ($width != -1 || $height != -1) | |
2926 $replaces[$image] = '[img' . ($width != -1 ? ' width=' . round($width) : '') . ($height != -1 ? ' height=' . round($height) : '') . ']' . $matches[7][$key] . '[/img]'; | |
2927 } | |
2928 if (!empty($replaces)) | |
2929 $value = str_replace(array_keys($replaces), array_values($replaces), $value); | |
2930 } | |
2931 } | |
2932 // Any disabled BBC? | |
2933 $disabledSigBBC = implode('|', $disabledTags); | |
2934 if (!empty($disabledSigBBC)) | |
2935 { | |
2936 if (preg_match('~\[(' . $disabledSigBBC . ')~i', $unparsed_signature, $matches) !== false && isset($matches[1])) | |
2937 { | |
2938 $disabledTags = array_unique($disabledTags); | |
2939 $txt['profile_error_signature_disabled_bbc'] = sprintf($txt['profile_error_signature_disabled_bbc'], implode(', ', $disabledTags)); | |
2940 return 'signature_disabled_bbc'; | |
2941 } | |
2942 } | |
2943 } | |
2944 | |
2945 preparsecode($value); | |
2946 return true; | |
2947 } | |
2948 | |
2949 // Validate an email address. | |
2950 function profileValidateEmail($email, $memID = 0) | |
2951 { | |
2952 global $smcFunc, $context; | |
2953 | |
2954 $email = strtr($email, array(''' => '\'')); | |
2955 | |
2956 // Check the name and email for validity. | |
2957 if (trim($email) == '') | |
2958 return 'no_email'; | |
2959 if (preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $email) == 0) | |
2960 return 'bad_email'; | |
2961 | |
2962 // Email addresses should be and stay unique. | |
2963 $request = $smcFunc['db_query']('', ' | |
2964 SELECT id_member | |
2965 FROM {db_prefix}members | |
2966 WHERE ' . ($memID != 0 ? 'id_member != {int:selected_member} AND ' : '') . ' | |
2967 email_address = {string:email_address} | |
2968 LIMIT 1', | |
2969 array( | |
2970 'selected_member' => $memID, | |
2971 'email_address' => $email, | |
2972 ) | |
2973 ); | |
2974 if ($smcFunc['db_num_rows']($request) > 0) | |
2975 return 'email_taken'; | |
2976 $smcFunc['db_free_result']($request); | |
2977 | |
2978 return true; | |
2979 } | |
2980 | |
2981 // Reload a users settings. | |
2982 function profileReloadUser() | |
2983 { | |
2984 global $sourcedir, $modSettings, $context, $cur_profile, $smcFunc, $profile_vars; | |
2985 | |
2986 // Log them back in - using the verify password as they must have matched and this one doesn't get changed by anyone! | |
2987 if (isset($_POST['passwrd2']) && $_POST['passwrd2'] != '') | |
2988 { | |
2989 require_once($sourcedir . '/Subs-Auth.php'); | |
2990 setLoginCookie(60 * $modSettings['cookieTime'], $context['id_member'], sha1(sha1(strtolower($cur_profile['member_name']) . un_htmlspecialchars($_POST['passwrd2'])) . $cur_profile['password_salt'])); | |
2991 } | |
2992 | |
2993 loadUserSettings(); | |
2994 writeLog(); | |
2995 } | |
2996 | |
2997 // Send the user a new activation email if they need to reactivate! | |
2998 function profileSendActivation() | |
2999 { | |
3000 global $sourcedir, $profile_vars, $txt, $context, $scripturl, $smcFunc, $cookiename, $cur_profile, $language, $modSettings; | |
3001 | |
3002 require_once($sourcedir . '/Subs-Post.php'); | |
3003 | |
3004 // Shouldn't happen but just in case. | |
3005 if (empty($profile_vars['email_address'])) | |
3006 return; | |
3007 | |
3008 $replacements = array( | |
3009 'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $context['id_member'] . ';code=' . $profile_vars['validation_code'], | |
3010 'ACTIVATIONCODE' => $profile_vars['validation_code'], | |
3011 'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $context['id_member'], | |
3012 ); | |
3013 | |
3014 // Send off the email. | |
3015 $emaildata = loadEmailTemplate('activate_reactivate', $replacements, empty($cur_profile['lngfile']) || empty($modSettings['userLanguage']) ? $language : $cur_profile['lngfile']); | |
3016 sendmail($profile_vars['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 0); | |
3017 | |
3018 // Log the user out. | |
3019 $smcFunc['db_query']('', ' | |
3020 DELETE FROM {db_prefix}log_online | |
3021 WHERE id_member = {int:selected_member}', | |
3022 array( | |
3023 'selected_member' => $context['id_member'], | |
3024 ) | |
3025 ); | |
3026 $_SESSION['log_time'] = 0; | |
3027 $_SESSION['login_' . $cookiename] = serialize(array(0, '', 0)); | |
3028 | |
3029 if (isset($_COOKIE[$cookiename])) | |
3030 $_COOKIE[$cookiename] = ''; | |
3031 | |
3032 loadUserSettings(); | |
3033 | |
3034 $context['user']['is_logged'] = false; | |
3035 $context['user']['is_guest'] = true; | |
3036 | |
3037 // Send them to the done-with-registration-login screen. | |
3038 loadTemplate('Register'); | |
3039 | |
3040 $context['page_title'] = $txt['profile']; | |
3041 $context['sub_template'] = 'after'; | |
3042 $context['title'] = $txt['activate_changed_email_title']; | |
3043 $context['description'] = $txt['activate_changed_email_desc']; | |
3044 | |
3045 // We're gone! | |
3046 obExit(); | |
3047 } | |
3048 | |
3049 // Function to allow the user to choose group membership etc... | |
3050 function groupMembership($memID) | |
3051 { | |
3052 global $txt, $scripturl, $user_profile, $user_info, $context, $modSettings, $smcFunc; | |
3053 | |
3054 $curMember = $user_profile[$memID]; | |
3055 $context['primary_group'] = $curMember['id_group']; | |
3056 | |
3057 // Can they manage groups? | |
3058 $context['can_manage_membergroups'] = allowedTo('manage_membergroups'); | |
3059 $context['can_manage_protected'] = allowedTo('admin_forum'); | |
3060 $context['can_edit_primary'] = $context['can_manage_protected']; | |
3061 $context['update_message'] = isset($_GET['msg']) && isset($txt['group_membership_msg_' . $_GET['msg']]) ? $txt['group_membership_msg_' . $_GET['msg']] : ''; | |
3062 | |
3063 // Get all the groups this user is a member of. | |
3064 $groups = explode(',', $curMember['additional_groups']); | |
3065 $groups[] = $curMember['id_group']; | |
3066 | |
3067 // Ensure the query doesn't croak! | |
3068 if (empty($groups)) | |
3069 $groups = array(0); | |
3070 // Just to be sure... | |
3071 foreach ($groups as $k => $v) | |
3072 $groups[$k] = (int) $v; | |
3073 | |
3074 // Get all the membergroups they can join. | |
3075 $request = $smcFunc['db_query']('', ' | |
3076 SELECT mg.id_group, mg.group_name, mg.description, mg.group_type, mg.online_color, mg.hidden, | |
3077 IFNULL(lgr.id_member, 0) AS pending | |
3078 FROM {db_prefix}membergroups AS mg | |
3079 LEFT JOIN {db_prefix}log_group_requests AS lgr ON (lgr.id_member = {int:selected_member} AND lgr.id_group = mg.id_group) | |
3080 WHERE (mg.id_group IN ({array_int:group_list}) | |
3081 OR mg.group_type > {int:nonjoin_group_id}) | |
3082 AND mg.min_posts = {int:min_posts} | |
3083 AND mg.id_group != {int:moderator_group} | |
3084 ORDER BY group_name', | |
3085 array( | |
3086 'group_list' => $groups, | |
3087 'selected_member' => $memID, | |
3088 'nonjoin_group_id' => 1, | |
3089 'min_posts' => -1, | |
3090 'moderator_group' => 3, | |
3091 ) | |
3092 ); | |
3093 // This beast will be our group holder. | |
3094 $context['groups'] = array( | |
3095 'member' => array(), | |
3096 'available' => array() | |
3097 ); | |
3098 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
3099 { | |
3100 // Can they edit their primary group? | |
3101 if (($row['id_group'] == $context['primary_group'] && $row['group_type'] > 1) || ($row['hidden'] != 2 && $context['primary_group'] == 0 && in_array($row['id_group'], $groups))) | |
3102 $context['can_edit_primary'] = true; | |
3103 | |
3104 // If they can't manage (protected) groups, and it's not publically joinable or already assigned, they can't see it. | |
3105 if (((!$context['can_manage_protected'] && $row['group_type'] == 1) || (!$context['can_manage_membergroups'] && $row['group_type'] == 0)) && $row['id_group'] != $context['primary_group']) | |
3106 continue; | |
3107 | |
3108 $context['groups'][in_array($row['id_group'], $groups) ? 'member' : 'available'][$row['id_group']] = array( | |
3109 'id' => $row['id_group'], | |
3110 'name' => $row['group_name'], | |
3111 'desc' => $row['description'], | |
3112 'color' => $row['online_color'], | |
3113 'type' => $row['group_type'], | |
3114 'pending' => $row['pending'], | |
3115 'is_primary' => $row['id_group'] == $context['primary_group'], | |
3116 'can_be_primary' => $row['hidden'] != 2, | |
3117 // Anything more than this needs to be done through account settings for security. | |
3118 'can_leave' => $row['id_group'] != 1 && $row['group_type'] > 1 ? true : false, | |
3119 ); | |
3120 } | |
3121 $smcFunc['db_free_result']($request); | |
3122 | |
3123 // Add registered members on the end. | |
3124 $context['groups']['member'][0] = array( | |
3125 'id' => 0, | |
3126 'name' => $txt['regular_members'], | |
3127 'desc' => $txt['regular_members_desc'], | |
3128 'type' => 0, | |
3129 'is_primary' => $context['primary_group'] == 0 ? true : false, | |
3130 'can_be_primary' => true, | |
3131 'can_leave' => 0, | |
3132 ); | |
3133 | |
3134 // No changing primary one unless you have enough groups! | |
3135 if (count($context['groups']['member']) < 2) | |
3136 $context['can_edit_primary'] = false; | |
3137 | |
3138 // In the special case that someone is requesting membership of a group, setup some special context vars. | |
3139 if (isset($_REQUEST['request']) && isset($context['groups']['available'][(int) $_REQUEST['request']]) && $context['groups']['available'][(int) $_REQUEST['request']]['type'] == 2) | |
3140 $context['group_request'] = $context['groups']['available'][(int) $_REQUEST['request']]; | |
3141 } | |
3142 | |
3143 // This function actually makes all the group changes... | |
3144 function groupMembership2($profile_vars, $post_errors, $memID) | |
3145 { | |
3146 global $user_info, $sourcedir, $context, $user_profile, $modSettings, $txt, $smcFunc, $scripturl, $language; | |
3147 | |
3148 // Let's be extra cautious... | |
3149 if (!$context['user']['is_owner'] || empty($modSettings['show_group_membership'])) | |
3150 isAllowedTo('manage_membergroups'); | |
3151 if (!isset($_REQUEST['gid']) && !isset($_POST['primary'])) | |
3152 fatal_lang_error('no_access', false); | |
3153 | |
3154 checkSession(isset($_GET['gid']) ? 'get' : 'post'); | |
3155 | |
3156 $old_profile = &$user_profile[$memID]; | |
3157 $context['can_manage_membergroups'] = allowedTo('manage_membergroups'); | |
3158 $context['can_manage_protected'] = allowedTo('admin_forum'); | |
3159 | |
3160 // By default the new primary is the old one. | |
3161 $newPrimary = $old_profile['id_group']; | |
3162 $addGroups = array_flip(explode(',', $old_profile['additional_groups'])); | |
3163 $canChangePrimary = $old_profile['id_group'] == 0 ? 1 : 0; | |
3164 $changeType = isset($_POST['primary']) ? 'primary' : (isset($_POST['req']) ? 'request' : 'free'); | |
3165 | |
3166 // One way or another, we have a target group in mind... | |
3167 $group_id = isset($_REQUEST['gid']) ? (int) $_REQUEST['gid'] : (int) $_POST['primary']; | |
3168 $foundTarget = $changeType == 'primary' && $group_id == 0 ? true : false; | |
3169 | |
3170 // Sanity check!! | |
3171 if ($group_id == 1) | |
3172 isAllowedTo('admin_forum'); | |
3173 // Protected groups too! | |
3174 else | |
3175 { | |
3176 $request = $smcFunc['db_query']('', ' | |
3177 SELECT group_type | |
3178 FROM {db_prefix}membergroups | |
3179 WHERE id_group = {int:current_group} | |
3180 LIMIT {int:limit}', | |
3181 array( | |
3182 'current_group' => $group_id, | |
3183 'limit' => 1, | |
3184 ) | |
3185 ); | |
3186 list ($is_protected) = $smcFunc['db_fetch_row']($request); | |
3187 $smcFunc['db_free_result']($request); | |
3188 | |
3189 if ($is_protected == 1) | |
3190 isAllowedTo('admin_forum'); | |
3191 } | |
3192 | |
3193 // What ever we are doing, we need to determine if changing primary is possible! | |
3194 $request = $smcFunc['db_query']('', ' | |
3195 SELECT id_group, group_type, hidden, group_name | |
3196 FROM {db_prefix}membergroups | |
3197 WHERE id_group IN ({int:group_list}, {int:current_group})', | |
3198 array( | |
3199 'group_list' => $group_id, | |
3200 'current_group' => $old_profile['id_group'], | |
3201 ) | |
3202 ); | |
3203 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
3204 { | |
3205 // Is this the new group? | |
3206 if ($row['id_group'] == $group_id) | |
3207 { | |
3208 $foundTarget = true; | |
3209 $group_name = $row['group_name']; | |
3210 | |
3211 // Does the group type match what we're doing - are we trying to request a non-requestable group? | |
3212 if ($changeType == 'request' && $row['group_type'] != 2) | |
3213 fatal_lang_error('no_access', false); | |
3214 // What about leaving a requestable group we are not a member of? | |
3215 elseif ($changeType == 'free' && $row['group_type'] == 2 && $old_profile['id_group'] != $row['id_group'] && !isset($addGroups[$row['id_group']])) | |
3216 fatal_lang_error('no_access', false); | |
3217 elseif ($changeType == 'free' && $row['group_type'] != 3 && $row['group_type'] != 2) | |
3218 fatal_lang_error('no_access', false); | |
3219 | |
3220 // We can't change the primary group if this is hidden! | |
3221 if ($row['hidden'] == 2) | |
3222 $canChangePrimary = false; | |
3223 } | |
3224 | |
3225 // If this is their old primary, can we change it? | |
3226 if ($row['id_group'] == $old_profile['id_group'] && ($row['group_type'] > 1 || $context['can_manage_membergroups']) && $canChangePrimary !== false) | |
3227 $canChangePrimary = 1; | |
3228 | |
3229 // If we are not doing a force primary move, don't do it automatically if current primary is not 0. | |
3230 if ($changeType != 'primary' && $old_profile['id_group'] != 0) | |
3231 $canChangePrimary = false; | |
3232 | |
3233 // If this is the one we are acting on, can we even act? | |
3234 if ((!$context['can_manage_protected'] && $row['group_type'] == 1) || (!$context['can_manage_membergroups'] && $row['group_type'] == 0)) | |
3235 $canChangePrimary = false; | |
3236 } | |
3237 $smcFunc['db_free_result']($request); | |
3238 | |
3239 // Didn't find the target? | |
3240 if (!$foundTarget) | |
3241 fatal_lang_error('no_access', false); | |
3242 | |
3243 // Final security check, don't allow users to promote themselves to admin. | |
3244 if ($context['can_manage_membergroups'] && !allowedTo('admin_forum')) | |
3245 { | |
3246 $request = $smcFunc['db_query']('', ' | |
3247 SELECT COUNT(permission) | |
3248 FROM {db_prefix}permissions | |
3249 WHERE id_group = {int:selected_group} | |
3250 AND permission = {string:admin_forum} | |
3251 AND add_deny = {int:not_denied}', | |
3252 array( | |
3253 'selected_group' => $group_id, | |
3254 'not_denied' => 1, | |
3255 'admin_forum' => 'admin_forum', | |
3256 ) | |
3257 ); | |
3258 list ($disallow) = $smcFunc['db_fetch_row']($request); | |
3259 $smcFunc['db_free_result']($request); | |
3260 | |
3261 if ($disallow) | |
3262 isAllowedTo('admin_forum'); | |
3263 } | |
3264 | |
3265 // If we're requesting, add the note then return. | |
3266 if ($changeType == 'request') | |
3267 { | |
3268 $request = $smcFunc['db_query']('', ' | |
3269 SELECT id_member | |
3270 FROM {db_prefix}log_group_requests | |
3271 WHERE id_member = {int:selected_member} | |
3272 AND id_group = {int:selected_group}', | |
3273 array( | |
3274 'selected_member' => $memID, | |
3275 'selected_group' => $group_id, | |
3276 ) | |
3277 ); | |
3278 if ($smcFunc['db_num_rows']($request) != 0) | |
3279 fatal_lang_error('profile_error_already_requested_group'); | |
3280 $smcFunc['db_free_result']($request); | |
3281 | |
3282 // Log the request. | |
3283 $smcFunc['db_insert']('', | |
3284 '{db_prefix}log_group_requests', | |
3285 array( | |
3286 'id_member' => 'int', 'id_group' => 'int', 'time_applied' => 'int', 'reason' => 'string-65534', | |
3287 ), | |
3288 array( | |
3289 $memID, $group_id, time(), $_POST['reason'], | |
3290 ), | |
3291 array('id_request') | |
3292 ); | |
3293 | |
3294 // Send an email to all group moderators etc. | |
3295 require_once($sourcedir . '/Subs-Post.php'); | |
3296 | |
3297 // Do we have any group moderators? | |
3298 $request = $smcFunc['db_query']('', ' | |
3299 SELECT id_member | |
3300 FROM {db_prefix}group_moderators | |
3301 WHERE id_group = {int:selected_group}', | |
3302 array( | |
3303 'selected_group' => $group_id, | |
3304 ) | |
3305 ); | |
3306 $moderators = array(); | |
3307 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
3308 $moderators[] = $row['id_member']; | |
3309 $smcFunc['db_free_result']($request); | |
3310 | |
3311 // Otherwise this is the backup! | |
3312 if (empty($moderators)) | |
3313 { | |
3314 require_once($sourcedir . '/Subs-Members.php'); | |
3315 $moderators = membersAllowedTo('manage_membergroups'); | |
3316 } | |
3317 | |
3318 if (!empty($moderators)) | |
3319 { | |
3320 $request = $smcFunc['db_query']('', ' | |
3321 SELECT id_member, email_address, lngfile, member_name, mod_prefs | |
3322 FROM {db_prefix}members | |
3323 WHERE id_member IN ({array_int:moderator_list}) | |
3324 AND notify_types != {int:no_notifications} | |
3325 ORDER BY lngfile', | |
3326 array( | |
3327 'moderator_list' => $moderators, | |
3328 'no_notifications' => 4, | |
3329 ) | |
3330 ); | |
3331 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
3332 { | |
3333 // Check whether they are interested. | |
3334 if (!empty($row['mod_prefs'])) | |
3335 { | |
3336 list(,, $pref_binary) = explode('|', $row['mod_prefs']); | |
3337 if (!($pref_binary & 4)) | |
3338 continue; | |
3339 } | |
3340 | |
3341 $replacements = array( | |
3342 'RECPNAME' => $row['member_name'], | |
3343 'APPYNAME' => $old_profile['member_name'], | |
3344 'GROUPNAME' => $group_name, | |
3345 'REASON' => $_POST['reason'], | |
3346 'MODLINK' => $scripturl . '?action=moderate;area=groups;sa=requests', | |
3347 ); | |
3348 | |
3349 $emaildata = loadEmailTemplate('request_membership', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']); | |
3350 sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 2); | |
3351 } | |
3352 $smcFunc['db_free_result']($request); | |
3353 } | |
3354 | |
3355 return $changeType; | |
3356 } | |
3357 // Otherwise we are leaving/joining a group. | |
3358 elseif ($changeType == 'free') | |
3359 { | |
3360 // Are we leaving? | |
3361 if ($old_profile['id_group'] == $group_id || isset($addGroups[$group_id])) | |
3362 { | |
3363 if ($old_profile['id_group'] == $group_id) | |
3364 $newPrimary = 0; | |
3365 else | |
3366 unset($addGroups[$group_id]); | |
3367 } | |
3368 // ... if not, must be joining. | |
3369 else | |
3370 { | |
3371 // Can we change the primary, and do we want to? | |
3372 if ($canChangePrimary) | |
3373 { | |
3374 if ($old_profile['id_group'] != 0) | |
3375 $addGroups[$old_profile['id_group']] = -1; | |
3376 $newPrimary = $group_id; | |
3377 } | |
3378 // Otherwise it's an additional group... | |
3379 else | |
3380 $addGroups[$group_id] = -1; | |
3381 } | |
3382 } | |
3383 // Finally, we must be setting the primary. | |
3384 elseif ($canChangePrimary) | |
3385 { | |
3386 if ($old_profile['id_group'] != 0) | |
3387 $addGroups[$old_profile['id_group']] = -1; | |
3388 if (isset($addGroups[$group_id])) | |
3389 unset($addGroups[$group_id]); | |
3390 $newPrimary = $group_id; | |
3391 } | |
3392 | |
3393 // Finally, we can make the changes! | |
3394 foreach ($addGroups as $id => $dummy) | |
3395 if (empty($id)) | |
3396 unset($addGroups[$id]); | |
3397 $addGroups = implode(',', array_flip($addGroups)); | |
3398 | |
3399 // Ensure that we don't cache permissions if the group is changing. | |
3400 if ($context['user']['is_owner']) | |
3401 $_SESSION['mc']['time'] = 0; | |
3402 else | |
3403 updateSettings(array('settings_updated' => time())); | |
3404 | |
3405 updateMemberData($memID, array('id_group' => $newPrimary, 'additional_groups' => $addGroups)); | |
3406 | |
3407 return $changeType; | |
3408 } | |
3409 | |
3410 ?> |