PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/forum/Sources/Profile-Modify.php

https://github.com/leftnode/nooges.com
PHP | 3301 lines | 2540 code | 323 blank | 438 comment | 526 complexity | f13a5509344f4a28addfe04d33411350 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**********************************************************************************
  3. * Profile-Modify.php *
  4. ***********************************************************************************
  5. * SMF: Simple Machines Forum *
  6. * Open-Source Project Inspired by Zef Hemel (zef@zefhemel.com) *
  7. * =============================================================================== *
  8. * Software Version: SMF 2.0 RC2 *
  9. * Software by: Simple Machines (http://www.simplemachines.org) *
  10. * Copyright 2006-2009 by: Simple Machines LLC (http://www.simplemachines.org) *
  11. * 2001-2006 by: Lewis Media (http://www.lewismedia.com) *
  12. * Support, News, Updates at: http://www.simplemachines.org *
  13. ***********************************************************************************
  14. * This program is free software; you may redistribute it and/or modify it under *
  15. * the terms of the provided license as published by Simple Machines LLC. *
  16. * *
  17. * This program is distributed in the hope that it is and will be useful, but *
  18. * WITHOUT ANY WARRANTIES; without even any implied warranty of MERCHANTABILITY *
  19. * or FITNESS FOR A PARTICULAR PURPOSE. *
  20. * *
  21. * See the "license.txt" file for details of the Simple Machines license. *
  22. * The latest version can always be found at http://www.simplemachines.org. *
  23. **********************************************************************************/
  24. if (!defined('SMF'))
  25. die('Hacking attempt...');
  26. /* This file has the primary job of showing and editing people's profiles.
  27. It also allows the user to change some of their or another's preferences,
  28. and such things. It uses the following functions:
  29. void loadProfileFields(bool force_reload = false)
  30. // !!!
  31. void setupProfileContext(array fields)
  32. // !!!
  33. void saveProfileFields()
  34. // !!!
  35. void saveProfileChanges(array &profile_variables, array &errors, int id_member)
  36. // !!!
  37. void makeThemeChanges(int id_member, int id_theme)
  38. // !!!
  39. void makeNotificationChanges(int id_member)
  40. // !!!
  41. void makeCustomFieldChanges(int id_member, string area, bool sanitize = true)
  42. // !!!
  43. void editBuddies(int id_member)
  44. // !!!
  45. void editIgnoreList(int id_member)
  46. // !!!
  47. void account(int id_member)
  48. // !!!
  49. void forumProfile(int id_member)
  50. // !!!
  51. void pmprefs(int id_member)
  52. // !!!
  53. array getAvatars(string directory, int level)
  54. // !!!
  55. void theme(int id_member)
  56. // !!!
  57. void authentication(int id_member, bool saving = false)
  58. // !!!
  59. void notification(int id_member)
  60. // !!!
  61. int list_getTopicNotificationCount(int memID)
  62. // !!!
  63. array list_getTopicNotifications(int start, int items_per_page, string sort, int memID)
  64. // !!!
  65. array list_getBoardNotifications(int start, int items_per_page, string sort, int memID)
  66. // !!!
  67. void loadThemeOptions(int id_member)
  68. // !!!
  69. void ignoreboards(int id_member)
  70. // !!!
  71. bool profileLoadLanguages()
  72. // !!!
  73. bool profileLoadGroups()
  74. // !!!
  75. bool profileLoadSignatureData()
  76. // !!!
  77. bool profileLoadAvatarData()
  78. // !!!
  79. bool profileSaveGroups(mixed &value)
  80. // !!!
  81. mixed profileSaveAvatarData(array &value)
  82. // !!!
  83. mixed profileValidateSignature(mixed &value)
  84. // !!!
  85. bool profileValidateEmail(string email, int id_member = none)
  86. // !!!
  87. void profileReloadUser()
  88. // !!!
  89. void profileSendActivation()
  90. // !!!
  91. void groupMembership(int id_member)
  92. // !!!
  93. mixed groupMembership2(array profile_vars, array post_erros, int id_member)
  94. // !!!
  95. Adding new fields to the profile:
  96. ---------------------------------------------------------------------------
  97. // !!!
  98. */
  99. // This defines every profile field known to man.
  100. function loadProfileFields($force_reload = false)
  101. {
  102. global $context, $profile_fields, $txt, $scripturl, $modSettings, $user_info, $old_profile, $smcFunc, $cur_profile, $language;
  103. // Don't load this twice!
  104. if (!empty($profile_fields) && !$force_reload)
  105. return;
  106. /* This horrific array defines all the profile fields in the whole world!
  107. In general each "field" has one array - the key of which is the database column name associated with said field. Each item
  108. can have the following attributes:
  109. string $type: The type of field this is - valid types are:
  110. - callback: This is a field which has its own callback mechanism for templating.
  111. - check: A simple checkbox.
  112. - hidden: This doesn't have any visual aspects but may have some validity.
  113. - password: A password box.
  114. - select: A select box.
  115. - text: A string of some description.
  116. string $label: The label for this item - default will be $txt[$key] if this isn't set.
  117. string $subtext: The subtext (Small label) for this item.
  118. int $size: Optional size for a text area.
  119. array $input_attr: An array of text strings to be added to the input box for this item.
  120. string $value: The value of the item. If not set $cur_profile[$key] is assumed.
  121. string $permission: Permission required for this item (Excluded _any/_own subfix which is applied automatically).
  122. function $input_validate: A runtime function which validates the element before going to the database. It is passed
  123. the relevant $_POST element if it exists and should be treated like a reference.
  124. Return types:
  125. - true: Element can be stored.
  126. - false: Skip this element.
  127. - a text string: An error occured - this is the error message.
  128. function $preload: A function that is used to load data required for this element to be displayed. Must return
  129. true to be displayed at all.
  130. string $cast_type: If set casts the element to a certain type. Valid types (bool, int, float).
  131. string $save_key: If the index of this element isn't the database column name it can be overriden
  132. with this string.
  133. bool $is_dummy: If set then nothing is acted upon for this element.
  134. bool $enabled: A test to determine whether this is even available - if not is unset.
  135. string $link_with: Key which links this field to an overall set.
  136. Note that all elements that have a custom input_validate must ensure they set the value of $cur_profile correct to enable
  137. the changes to be displayed correctly on submit of the form.
  138. */
  139. $profile_fields = array(
  140. 'aim' => array(
  141. 'type' => 'text',
  142. 'label' => $txt['aim'],
  143. 'subtext' => $txt['your_aim'],
  144. 'size' => 24,
  145. 'value' => strtr(empty($cur_profile['aim']) ? '' : $cur_profile['aim'], '+', ' '),
  146. 'permission' => 'profile_extra',
  147. 'input_validate' => create_function('&$value', '
  148. $value = strtr($value, \' \', \'+\');
  149. return true;
  150. '),
  151. ),
  152. 'avatar_choice' => array(
  153. 'type' => 'callback',
  154. 'callback_func' => 'avatar_select',
  155. // This handles the permissions too.
  156. 'preload' => 'profileLoadAvatarData',
  157. 'input_validate' => 'profileSaveAvatarData',
  158. 'save_key' => 'avatar',
  159. ),
  160. 'bday1' => array(
  161. 'type' => 'callback',
  162. 'callback_func' => 'birthdate',
  163. 'permission' => 'profile_extra',
  164. 'preload' => create_function('', '
  165. global $cur_profile, $context;
  166. // Split up the birthdate....
  167. list ($uyear, $umonth, $uday) = explode(\'-\', empty($cur_profile[\'birthdate\']) || $cur_profile[\'birthdate\'] == \'0001-01-01\' ? \'0000-00-00\' : $cur_profile[\'birthdate\']);
  168. $context[\'member\'][\'birth_date\'] = array(
  169. \'year\' => $uyear == \'0004\' ? \'0000\' : $uyear,
  170. \'month\' => $umonth,
  171. \'day\' => $uday,
  172. );
  173. return true;
  174. '),
  175. 'input_validate' => create_function('&$value', '
  176. global $profile_vars, $cur_profile;
  177. if (isset($_POST[\'bday2\'], $_POST[\'bday3\']) && $value > 0 && $_POST[\'bday2\'] > 0)
  178. {
  179. // Set to blank?
  180. if ((int) $_POST[\'bday3\'] == 1 && (int) $_POST[\'bday2\'] == 1 && (int) $value == 1)
  181. $value = \'0001-01-01\';
  182. else
  183. $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\';
  184. }
  185. else
  186. $value = \'0001-01-01\';
  187. $profile_vars[\'birthdate\'] = $value;
  188. $cur_profile[\'birthdate\'] = $value;
  189. return false;
  190. '),
  191. ),
  192. // Setting the birthdate the old style way?
  193. 'birthdate' => array(
  194. 'type' => 'hidden',
  195. 'permission' => 'profile_extra',
  196. 'input_validate' => create_function('&$value', '
  197. global $cur_profile;
  198. // !!! Should we check for this year and tell them they made a mistake :P? (based on coppa at least?)
  199. if (preg_match(\'/(\d{4})[\-\., ](\d{2})[\-\., ](\d{2})/\', $value, $dates) === 1)
  200. {
  201. $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\';
  202. return true;
  203. }
  204. else
  205. {
  206. $value = empty($cur_profile[\'birthdate\']) ? \'0001-01-01\' : $cur_profile[\'birthdate\'];
  207. return false;
  208. }
  209. '),
  210. ),
  211. 'date_registered' => array(
  212. 'type' => 'text',
  213. '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),
  214. 'label' => $txt['date_registered'],
  215. 'log_change' => true,
  216. 'permission' => 'moderate_forum',
  217. 'input_validate' => create_function('&$value', '
  218. global $txt, $user_info, $modSettings, $cur_profile, $context;
  219. // Bad date! Go try again - please?
  220. if (($value = strtotime($value)) === -1)
  221. {
  222. $value = $cur_profile[\'date_registered\'];
  223. 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));
  224. }
  225. // As long as it doesn\'t equal "N/A"...
  226. elseif ($value != $txt[\'not_applicable\'] && $value != strtotime(strftime(\'%Y-%m-%d\', $cur_profile[\'date_registered\'] + ($user_info[\'time_offset\'] + $modSettings[\'time_offset\']) * 3600)))
  227. $value = $value - ($user_info[\'time_offset\'] + $modSettings[\'time_offset\']) * 3600;
  228. else
  229. $value = $cur_profile[\'date_registered\'];
  230. return true;
  231. '),
  232. ),
  233. 'email_address' => array(
  234. 'type' => 'text',
  235. 'label' => $txt['email'],
  236. 'subtext' => $txt['valid_email'],
  237. 'log_change' => true,
  238. 'permission' => 'profile_identity',
  239. 'input_validate' => create_function('&$value', '
  240. global $context, $old_profile, $context, $profile_vars, $sourcedir, $modSettings;
  241. if (strtolower($value) == strtolower($old_profile[\'email_address\']))
  242. return false;
  243. $isValid = profileValidateEmail($value, $context[\'id_member\']);
  244. // Do they need to revalidate? If so schedule the function!
  245. if ($isValid === true && !empty($modSettings[\'send_validation_onChange\']) && !allowedTo(\'moderate_forum\'))
  246. {
  247. require_once($sourcedir . \'/Subs-Members.php\');
  248. $profile_vars[\'validation_code\'] = generateValidationCode();
  249. $profile_vars[\'is_activated\'] = 2;
  250. $context[\'profile_execute_on_save\'][] = \'profileSendActivation\';
  251. unset($context[\'profile_execute_on_save\'][\'reload_user\']);
  252. }
  253. return $isValid;
  254. '),
  255. ),
  256. 'gender' => array(
  257. 'type' => 'select',
  258. 'cast_type' => 'int',
  259. 'options' => 'return array(0 => \'\', 1 => $txt[\'male\'], 2 => $txt[\'female\']);',
  260. 'label' => $txt['gender'],
  261. 'permission' => 'profile_extra',
  262. ),
  263. 'hide_email' => array(
  264. 'type' => 'check',
  265. 'value' => empty($cur_profile['hide_email']) ? true : false,
  266. 'label' => $txt['allow_user_email'],
  267. 'permission' => 'profile_identity',
  268. 'input_validate' => create_function('&$value', '
  269. $value = $value == 0 ? 1 : 0;
  270. return true;
  271. '),
  272. ),
  273. 'icq' => array(
  274. 'type' => 'text',
  275. 'label' => $txt['icq'],
  276. 'subtext' => $txt['your_icq'],
  277. 'size' => 24,
  278. 'permission' => 'profile_extra',
  279. // Need to make sure ICQ doesn't equal 0.
  280. 'input_validate' => create_function('&$value', '
  281. if (empty($value))
  282. $value = \'\';
  283. else
  284. $value = (int) $value;
  285. return true;
  286. '),
  287. ),
  288. // Selecting group membership is a complicated one so we treat it separate!
  289. 'id_group' => array(
  290. 'type' => 'callback',
  291. 'callback_func' => 'group_manage',
  292. 'permission' => 'manage_membergroups',
  293. 'preload' => 'profileLoadGroups',
  294. 'input_validate' => 'profileSaveGroups',
  295. ),
  296. 'id_theme' => array(
  297. 'type' => 'callback',
  298. 'callback_func' => 'theme_pick',
  299. 'permission' => 'profile_extra',
  300. 'enabled' => $modSettings['theme_allow'] || allowedTo('admin_forum'),
  301. 'preload' => create_function('', '
  302. global $smcFunc, $context, $cur_profile, $txt;
  303. $request = $smcFunc[\'db_query\'](\'\', \'
  304. SELECT value
  305. FROM {db_prefix}themes
  306. WHERE id_theme = {int:id_theme}
  307. AND variable = {string:variable}
  308. LIMIT 1\', array(
  309. \'id_theme\' => $cur_profile[\'id_theme\'],
  310. \'variable\' => \'name\',
  311. )
  312. );
  313. list ($name) = $smcFunc[\'db_fetch_row\']($request);
  314. $smcFunc[\'db_free_result\']($request);
  315. $context[\'member\'][\'theme\'] = array(
  316. \'id\' => $cur_profile[\'id_theme\'],
  317. \'name\' => empty($cur_profile[\'id_theme\']) ? $txt[\'theme_forum_default\'] : $name
  318. );
  319. return true;
  320. '),
  321. 'input_validate' => create_function('&$value', '
  322. $value = (int) $value;
  323. return true;
  324. '),
  325. ),
  326. 'karma_good' => array(
  327. 'type' => 'callback',
  328. 'callback_func' => 'karma_modify',
  329. 'subtext' => $txt['your_icq'],
  330. 'permission' => 'admin_forum',
  331. // Set karma_bad too!
  332. 'input_validate' => create_function('&$value', '
  333. global $profile_vars, $cur_profile;
  334. $value = (int) $value;
  335. if (isset($_POST[\'karma_bad\']))
  336. {
  337. $profile_vars[\'karma_bad\'] = $_POST[\'karma_bad\'] != \'\' ? (int) $_POST[\'karma_bad\'] : 0;
  338. $cur_profile[\'karma_bad\'] = $_POST[\'karma_bad\'] != \'\' ? (int) $_POST[\'karma_bad\'] : 0;
  339. }
  340. return true;
  341. '),
  342. 'preload' => create_function('', '
  343. global $context, $cur_profile;
  344. $context[\'member\'][\'karma\'][\'good\'] = $cur_profile[\'karma_good\'];
  345. $context[\'member\'][\'karma\'][\'bad\'] = $cur_profile[\'karma_bad\'];
  346. return true;
  347. '),
  348. 'enabled' => !empty($modSettings['karmaMode']),
  349. ),
  350. 'lngfile' => array(
  351. 'type' => 'select',
  352. 'options' => 'return $context[\'profile_languages\'];',
  353. 'label' => $txt['preferred_language'],
  354. 'permission' => 'profile_identity',
  355. 'preload' => 'profileLoadLanguages',
  356. 'enabled' => !empty($modSettings['userLanguage']),
  357. 'value' => empty($cur_profile['lngfile']) ? $language : $cur_profile['lngfile'],
  358. 'input_validate' => create_function('&$value', '
  359. global $context, $cur_profile;
  360. // Load the languages.
  361. profileLoadLanguages();
  362. if (isset($context[\'profile_languages\'][$value]))
  363. {
  364. if ($context[\'user\'][\'is_owner\'])
  365. $_SESSION[\'language\'] = $value;
  366. return true;
  367. }
  368. else
  369. {
  370. $value = $cur_profile[\'lngfile\'];
  371. return false;
  372. }
  373. '),
  374. ),
  375. 'location' => array(
  376. 'type' => 'text',
  377. 'label' => $txt['location'],
  378. 'log_change' => true,
  379. 'size' => 50,
  380. 'permission' => 'profile_extra',
  381. ),
  382. // The username is not always editable - so adjust it as such.
  383. 'member_name' => array(
  384. 'type' => allowedTo('admin_forum') && isset($_GET['changeusername']) ? 'text' : 'label',
  385. 'label' => $txt['username'],
  386. '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>)' : '',
  387. 'log_change' => true,
  388. 'permission' => 'profile_identity',
  389. 'prehtml' => allowedTo('admin_forum') && isset($_GET['changeusername']) ? '<div class="alert">' . $txt['username_warning'] . '</div>' : '',
  390. 'input_validate' => create_function('&$value', '
  391. global $sourcedir, $context, $user_info;
  392. if (allowedTo(\'admin_forum\'))
  393. {
  394. // We\'ll need this...
  395. require_once($sourcedir . \'/Subs-Auth.php\');
  396. // Maybe they are trying to change their password as well?
  397. $resetPassword = true;
  398. if (isset($_POST[\'passwrd2\']) && isset($_POST[\'passwrd1\']) && (($_POST[\'passwrd1\'] != $_POST[\'passwrd2\']) || (validatePassword($value, $value, array($user_info[\'name\'], $user_info[\'email\'])) == null)))
  399. $resetPassword = false;
  400. // Do the reset... this will send them an email too.
  401. if ($resetPassword)
  402. resetPassword($context[\'id_member\'], $value);
  403. elseif ($value !== null)
  404. {
  405. validateUsername($context[\'id_member\'], $value);
  406. updateMemberData($context[\'id_member\'], array(\'member_name\' => $value));
  407. }
  408. }
  409. return false;
  410. '),
  411. ),
  412. 'msn' => array(
  413. 'type' => 'text',
  414. 'label' => $txt['msn'],
  415. 'subtext' => $txt['msn_email_address'],
  416. 'size' => 24,
  417. 'permission' => 'profile_extra',
  418. 'input_validate' => create_function('&$value', '
  419. global $cur_profile;
  420. // Make sure the msn one is an email address, not something like \'none\' :P.
  421. if ($value != \'\' && preg_match(\'~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\\\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~\', $value) == 0)
  422. {
  423. $value = $cur_profile[\'msn\'];
  424. return false;
  425. }
  426. return true;
  427. '),
  428. ),
  429. 'passwrd1' => array(
  430. 'type' => 'password',
  431. 'label' => $txt['choose_pass'],
  432. 'subtext' => $txt['password_strength'],
  433. 'size' => 20,
  434. 'value' => '',
  435. 'enabled' => empty($cur_profile['openid_uri']),
  436. 'permission' => 'profile_identity',
  437. 'save_key' => 'passwd',
  438. // Note this will only work if passwrd2 also exists!
  439. 'input_validate' => create_function('&$value', '
  440. global $sourcedir, $user_info, $smcFunc, $cur_profile;
  441. // If we didn\'t try it then ignore it!
  442. if ($value == \'\')
  443. return false;
  444. // Do the two entries for the password even match?
  445. if (!isset($_POST[\'passwrd2\']) || $value != $_POST[\'passwrd2\'])
  446. return \'bad_new_password\';
  447. // Let\'s get the validation function into play...
  448. require_once($sourcedir . \'/Subs-Auth.php\');
  449. $passwordErrors = validatePassword($value, $cur_profile[\'member_name\'], array($cur_profile[\'real_name\'], $user_info[\'username\'], $user_info[\'name\'], $user_info[\'email\']));
  450. // Were there errors?
  451. if ($passwordErrors != null)
  452. return \'password_\' . $passwordErrors;
  453. // Set up the new password variable... ready for storage.
  454. $value = sha1(strtolower($cur_profile[\'member_name\']) . un_htmlspecialchars($value));
  455. return true;
  456. '),
  457. ),
  458. 'passwrd2' => array(
  459. 'type' => 'password',
  460. 'label' => $txt['verify_pass'],
  461. 'enabled' => empty($cur_profile['openid_uri']),
  462. 'size' => 20,
  463. 'value' => '',
  464. 'permission' => 'profile_identity',
  465. 'is_dummy' => true,
  466. ),
  467. 'personal_text' => array(
  468. 'type' => 'text',
  469. 'label' => $txt['personal_text'],
  470. 'log_change' => true,
  471. 'input_attr' => array('maxlength="50"'),
  472. 'size' => 50,
  473. 'permission' => 'profile_extra',
  474. ),
  475. // This does ALL the pm settings
  476. 'pm_prefs' => array(
  477. 'type' => 'callback',
  478. 'callback_func' => 'pm_settings',
  479. 'permission' => 'pm_read',
  480. 'preload' => create_function('', '
  481. global $context, $cur_profile;
  482. $context[\'display_mode\'] = $cur_profile[\'pm_prefs\'] & 3;
  483. $context[\'send_email\'] = $cur_profile[\'pm_email_notify\'];
  484. $context[\'receive_from\'] = $cur_profile[\'pm_receive_from\'];
  485. return true;
  486. '),
  487. 'input_validate' => create_function('&$value', '
  488. global $cur_profile, $profile_vars;
  489. // Simple validate and apply the two "sub settings"
  490. $value = max(min($value, 2), 0);
  491. $cur_profile[\'pm_email_notify\'] = $profile_vars[\'pm_email_notify\'] = max(min((int) $_POST[\'pm_email_notify\'], 2), 0);
  492. $cur_profile[\'pm_receive_from\'] = $profile_vars[\'pm_receive_from\'] = max(min((int) $_POST[\'pm_receive_from\'], 4), 0);
  493. return true;
  494. '),
  495. ),
  496. 'posts' => array(
  497. 'type' => 'int',
  498. 'label' => $txt['profile_posts'],
  499. 'log_change' => true,
  500. 'size' => 7,
  501. 'permission' => 'moderate_forum',
  502. 'input_validate' => create_function('&$value', '
  503. $value = $value != \'\' ? strtr($value, array(\',\' => \'\', \'.\' => \'\', \' \' => \'\')) : 0;
  504. return true;
  505. '),
  506. ),
  507. 'real_name' => array(
  508. 'type' => !empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum') ? 'text' : 'label',
  509. 'label' => $txt['name'],
  510. 'subtext' => $txt['display_name_desc'],
  511. 'log_change' => true,
  512. 'input_attr' => array('maxlength="60"'),
  513. 'permission' => 'profile_identity',
  514. 'enabled' => !empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum'),
  515. 'input_validate' => create_function('&$value', '
  516. global $context, $smcFunc, $sourcedir, $cur_profile;
  517. $value = trim(preg_replace(\'~[\s]~\' . ($context[\'utf8\'] ? \'u\' : \'\'), \' \', $value));
  518. if (trim($value) == \'\')
  519. return \'no_name\';
  520. elseif ($smcFunc[\'strlen\']($value) > 60)
  521. return \'name_too_long\';
  522. elseif ($cur_profile[\'real_name\'] != $value)
  523. {
  524. require_once($sourcedir . \'/Subs-Members.php\');
  525. if (isReservedName($value, $context[\'id_member\']))
  526. return \'name_taken\';
  527. }
  528. return true;
  529. '),
  530. ),
  531. 'secret_question' => array(
  532. 'type' => 'text',
  533. 'label' => $txt['secret_question'],
  534. 'subtext' => $txt['secret_desc'],
  535. 'size' => 50,
  536. 'permission' => 'profile_identity',
  537. ),
  538. 'secret_answer' => array(
  539. 'type' => 'text',
  540. 'label' => $txt['secret_answer'],
  541. 'subtext' => $txt['secret_desc2'],
  542. 'size' => 20,
  543. '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>',
  544. 'value' => '',
  545. 'permission' => 'profile_identity',
  546. 'input_validate' => create_function('&$value', '
  547. $value = $value != \'\' ? md5($value) : \'\';
  548. return true;
  549. '),
  550. ),
  551. 'signature' => array(
  552. 'type' => 'callback',
  553. 'callback_func' => 'signature_modify',
  554. 'permission' => 'profile_extra',
  555. 'enabled' => substr($modSettings['signature_settings'], 0, 1) == 1,
  556. 'preload' => 'profileLoadSignatureData',
  557. 'input_validate' => 'profileValidateSignature',
  558. ),
  559. 'show_online' => array(
  560. 'type' => 'check',
  561. 'label' => $txt['show_online'],
  562. 'permission' => 'profile_identity',
  563. 'enabled' => !empty($modSettings['allow_hideOnline']) || allowedTo('moderate_forum'),
  564. ),
  565. 'smiley_set' => array(
  566. 'type' => 'callback',
  567. 'callback_func' => 'smiley_pick',
  568. 'enabled' => !empty($modSettings['smiley_sets_enable']),
  569. 'permission' => 'profile_extra',
  570. 'preload' => create_function('', '
  571. global $modSettings, $context, $txt, $cur_profile;
  572. $context[\'member\'][\'smiley_set\'][\'id\'] = empty($cur_profile[\'smiley_set\']) ? \'\' : $cur_profile[\'smiley_set\'];
  573. $context[\'smiley_sets\'] = explode(\',\', \'none,,\' . $modSettings[\'smiley_sets_known\']);
  574. $set_names = explode("\n", $txt[\'smileys_none\'] . "\n" . $txt[\'smileys_forum_board_default\'] . "\n" . $modSettings[\'smiley_sets_names\']);
  575. foreach ($context[\'smiley_sets\'] as $i => $set)
  576. {
  577. $context[\'smiley_sets\'][$i] = array(
  578. \'id\' => $set,
  579. \'name\' => $set_names[$i],
  580. \'selected\' => $set == $context[\'member\'][\'smiley_set\'][\'id\']
  581. );
  582. if ($context[\'smiley_sets\'][$i][\'selected\'])
  583. $context[\'member\'][\'smiley_set\'][\'name\'] = $set_names[$i];
  584. }
  585. return true;
  586. '),
  587. 'input_validate' => create_function('&$value', '
  588. global $modSettings;
  589. $smiley_sets = explode(\',\', $modSettings[\'smiley_sets_known\']);
  590. if (!in_array($value, $smiley_sets) && $value != \'none\')
  591. $value = \'\';
  592. return true;
  593. '),
  594. ),
  595. // Pretty much a dummy entry - it populates all the theme settings.
  596. 'theme_settings' => array(
  597. 'type' => 'callback',
  598. 'callback_func' => 'theme_settings',
  599. 'permission' => 'profile_extra',
  600. 'is_dummy' => true,
  601. 'preload' => create_function('', '
  602. loadLanguage(\'Settings\');
  603. return true;
  604. '),
  605. ),
  606. 'time_format' => array(
  607. 'type' => 'callback',
  608. 'callback_func' => 'timeformat_modify',
  609. 'permission' => 'profile_extra',
  610. 'preload' => create_function('', '
  611. global $context, $user_info, $txt, $cur_profile, $modSettings;
  612. $context[\'easy_timeformats\'] = array(
  613. array(\'format\' => \'\', \'title\' => $txt[\'timeformat_default\']),
  614. array(\'format\' => \'%B %d, %Y, %I:%M:%S %p\', \'title\' => $txt[\'timeformat_easy1\']),
  615. array(\'format\' => \'%B %d, %Y, %H:%M:%S\', \'title\' => $txt[\'timeformat_easy2\']),
  616. array(\'format\' => \'%Y-%m-%d, %H:%M:%S\', \'title\' => $txt[\'timeformat_easy3\']),
  617. array(\'format\' => \'%d %B %Y, %H:%M:%S\', \'title\' => $txt[\'timeformat_easy4\']),
  618. array(\'format\' => \'%d-%m-%Y, %H:%M:%S\', \'title\' => $txt[\'timeformat_easy5\'])
  619. );
  620. $context[\'member\'][\'time_format\'] = $cur_profile[\'time_format\'];
  621. $context[\'current_forum_time\'] = timeformat(time() - $user_info[\'time_offset\'] * 3600, false);
  622. $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);
  623. $context[\'current_forum_time_hour\'] = (int) strftime(\'%H\', forum_time(false));
  624. return true;
  625. '),
  626. ),
  627. 'time_offset' => array(
  628. 'type' => 'callback',
  629. 'callback_func' => 'timeoffset_modify',
  630. 'permission' => 'profile_extra',
  631. 'preload' => create_function('', '
  632. global $context, $cur_profile;
  633. $context[\'member\'][\'time_offset\'] = $cur_profile[\'time_offset\'];
  634. return true;
  635. '),
  636. 'input_validate' => create_function('&$value', '
  637. // Validate the time_offset...
  638. $value = (float) strtr($value, \',\', \'.\');
  639. if ($value < -23.5 || $value > 23.5)
  640. return \'bad_offset\';
  641. return true;
  642. '),
  643. ),
  644. 'usertitle' => array(
  645. 'type' => 'text',
  646. 'label' => $txt['custom_title'],
  647. 'log_change' => true,
  648. 'size' => 50,
  649. 'permission' => 'profile_title',
  650. 'enabled' => !empty($modSettings['titlesEnable']),
  651. ),
  652. 'website_title' => array(
  653. 'type' => 'text',
  654. 'label' => $txt['website_title'],
  655. 'subtext' => $txt['include_website_url'],
  656. 'size' => 50,
  657. 'permission' => 'profile_extra',
  658. 'link_with' => 'website',
  659. ),
  660. 'website_url' => array(
  661. 'type' => 'text',
  662. 'label' => $txt['website_url'],
  663. 'subtext' => $txt['complete_url'],
  664. 'size' => 50,
  665. 'permission' => 'profile_extra',
  666. // Fix the URL...
  667. 'input_validate' => create_function('&$value', '
  668. if (strlen(trim($value)) > 0 && strpos($value, \'://\') === false)
  669. $value = \'http://\' . $value;
  670. if (strlen($value) < 8)
  671. $value = \'\';
  672. return true;
  673. '),
  674. 'link_with' => 'website',
  675. ),
  676. 'yim' => array(
  677. 'type' => 'text',
  678. 'label' => $txt['yim'],
  679. 'subtext' => $txt['your_yim'],
  680. 'size' => 24,
  681. 'input_attr' => array('maxlength="32"'),
  682. 'permission' => 'profile_extra',
  683. ),
  684. );
  685. $disabled_fields = !empty($modSettings['disabled_profile_fields']) ? explode(',', $modSettings['disabled_profile_fields']) : array();
  686. // For each of the above let's take out the bits which don't apply - to save memory and security!
  687. foreach ($profile_fields as $key => $field)
  688. {
  689. // Do we have permission to do this?
  690. if (isset($field['permission']) && !allowedTo(($context['user']['is_owner'] ? array($field['permission'] . '_own', $field['permission'] . '_any') : $field['permission'] . '_any')) && !allowedTo($field['permission']))
  691. unset($profile_fields[$key]);
  692. // Is it enabled?
  693. if (isset($field['enabled']) && !$field['enabled'])
  694. unset($profile_fields[$key]);
  695. // Is it specifically disabled?
  696. if (in_array($key, $disabled_fields) || (isset($field['link_with']) && in_array($field['link_with'], $disabled_fields)))
  697. unset($profile_fields[$key]);
  698. }
  699. }
  700. // Setup the context for a page load!
  701. function setupProfileContext($fields)
  702. {
  703. global $profile_fields, $context, $cur_profile, $smcFunc;
  704. // Make sure we have this!
  705. loadProfileFields(true);
  706. // First check for any linked sets.
  707. foreach ($profile_fields as $key => $field)
  708. if (isset($field['link_with']) && in_array($field['link_with'], $fields))
  709. $fields[] = $key;
  710. // Some default bits.
  711. $context['profile_prehtml'] = '';
  712. $context['profile_posthtml'] = '';
  713. $context['profile_javascript'] = '';
  714. $context['profile_onsubmit_javascript'] = '';
  715. $i = 0;
  716. $last_type = '';
  717. foreach ($fields as $key => $field)
  718. {
  719. if (isset($profile_fields[$field]))
  720. {
  721. // Shortcut.
  722. $cur_field = &$profile_fields[$field];
  723. // Does it have a preload and does that preload succeed?
  724. if (isset($cur_field['preload']) && !$cur_field['preload']())
  725. continue;
  726. // If this is anything but complex we need to do more cleaning!
  727. if ($cur_field['type'] != 'callback' && $cur_field['type'] != 'hidden')
  728. {
  729. if (!isset($cur_field['label']))
  730. $cur_field['label'] = isset($txt[$field]) ? $txt[$field] : $field;
  731. // Everything has a value!
  732. if (!isset($cur_field['value']))
  733. {
  734. $cur_field['value'] = isset($cur_profile[$field]) ? $cur_profile[$field] : '';
  735. }
  736. // Any input attributes?
  737. $cur_field['input_attr'] = !empty($cur_field['input_attr']) ? implode(',', $cur_field['input_attr']) : '';
  738. }
  739. // Was there an error with this field on posting?
  740. if (isset($context['profile_errors'][$field]))
  741. $cur_field['is_error'] = true;
  742. // Any javascript stuff?
  743. if (!empty($cur_field['js_submit']))
  744. $context['profile_onsubmit_javascript'] .= $cur_field['js_submit'];
  745. if (!empty($cur_field['js']))
  746. $context['profile_javascript'] .= $cur_field['js'];
  747. // Any template stuff?
  748. if (!empty($cur_field['prehtml']))
  749. $context['profile_prehtml'] .= $cur_field['prehtml'];
  750. if (!empty($cur_field['posthtml']))
  751. $context['profile_posthtml'] .= $cur_field['posthtml'];
  752. // Finally put it into context?
  753. if ($cur_field['type'] != 'hidden')
  754. {
  755. $last_type = $cur_field['type'];
  756. $context['profile_fields'][$field] = &$profile_fields[$field];
  757. }
  758. }
  759. // Bodge in a line break - without doing two in a row ;)
  760. elseif ($field == 'hr' && $last_type != 'hr' && $last_type != '')
  761. {
  762. $last_type = 'hr';
  763. $context['profile_fields'][$i++]['type'] = 'hr';
  764. }
  765. }
  766. // Free up some memory.
  767. unset($profile_fields);
  768. }
  769. // Save the profile changes.
  770. function saveProfileFields()
  771. {
  772. global $profile_fields, $profile_vars, $context, $old_profile, $post_errors, $sourcedir, $modSettings, $cur_profile, $smcFunc;
  773. // Load them up.
  774. loadProfileFields();
  775. // This makes things easier...
  776. $old_profile = $cur_profile;
  777. // This allows variables to call activities when they save - by default just to reload their settings
  778. $context['profile_execute_on_save'] = array();
  779. if ($context['user']['is_owner'])
  780. $context['profile_execute_on_save']['reload_user'] = 'profileReloadUser';
  781. // Assume we log nothing.
  782. $context['log_changes'] = array();
  783. // Cycle through the profile fields working out what to do!
  784. foreach ($profile_fields as $key => $field)
  785. {
  786. if (!isset($_POST[$key]) || !empty($field['is_dummy']))
  787. continue;
  788. // What gets updated?
  789. $db_key = isset($field['save_key']) ? $field['save_key'] : $key;
  790. // Right - we have something that is enabled, we can act upon and has a value posted to it. Does it have a validation function?
  791. if (isset($field['input_validate']))
  792. {
  793. $is_valid = $field['input_validate']($_POST[$key]);
  794. // An error occured - set it as such!
  795. if ($is_valid !== true)
  796. {
  797. // Is this an actual error?
  798. if ($is_valid !== false)
  799. {
  800. $post_errors[$key] = $is_valid;
  801. $profile_fields[$key]['is_error'] = $is_valid;
  802. }
  803. // Retain the old value.
  804. $cur_profile[$key] = $_POST[$key];
  805. continue;
  806. }
  807. }
  808. // Are we doing a cast?
  809. $field['cast_type'] = empty($field['cast_type']) ? $field['type'] : $field['cast_type'];
  810. // Finally, clean up certain types.
  811. if ($field['cast_type'] == 'int')
  812. $_POST[$key] = (int) $_POST[$key];
  813. elseif ($field['cast_type'] == 'float')
  814. $_POST[$key] = (float) $_POST[$key];
  815. elseif ($field['cast_type'] == 'check')
  816. $_POST[$key] = !empty($_POST[$key]) ? 1 : 0;
  817. // If we got here we're doing OK.
  818. if ($field['type'] != 'hidden' && (!isset($old_profile[$key]) || $_POST[$key] != $old_profile[$key]))
  819. {
  820. // Set the save variable.
  821. $profile_vars[$db_key] = $_POST[$key];
  822. // And update the user profile.
  823. $cur_profile[$key] = $_POST[$key];
  824. // Are we logging it?
  825. if (!empty($field['log_change']) && isset($old_profile[$key]))
  826. $context['log_changes'][$key] = array(
  827. 'previous' => $old_profile[$key],
  828. 'new' => $_POST[$key],
  829. );
  830. }
  831. }
  832. //!!! Temporary
  833. if ($context['user']['is_owner'])
  834. $changeOther = allowedTo(array('profile_extra_any', 'profile_extra_own'));
  835. else
  836. $changeOther = allowedTo('profile_extra_any');
  837. if ($changeOther)
  838. {
  839. makeThemeChanges($context['id_member'], isset($_POST['id_theme']) ? (int) $_POST['id_theme'] : $old_profile['id_theme']);
  840. if (!empty($_REQUEST['sa']))
  841. makeCustomFieldChanges($context['id_member'], $_REQUEST['sa'], false);
  842. }
  843. // Free memory!
  844. unset($profile_fields);
  845. }
  846. // Save the profile changes....
  847. function saveProfileChanges(&$profile_vars, &$post_errors, $memID)
  848. {
  849. global $user_info, $txt, $modSettings, $user_profile;
  850. global $context, $settings, $sourcedir;
  851. global $smcFunc;
  852. // These make life easier....
  853. $old_profile = &$user_profile[$memID];
  854. // Permissions...
  855. if ($context['user']['is_owner'])
  856. {
  857. $changeIdentity = allowedTo(array('profile_identity_any', 'profile_identity_own'));
  858. $changeOther = allowedTo(array('profile_extra_any', 'profile_extra_own'));
  859. }
  860. else
  861. {
  862. $changeIdentity = allowedTo('profile_identity_any');
  863. $changeOther = allowedTo('profile_extra_any');
  864. }
  865. // Arrays of all the changes - makes things easier.
  866. $profile_bools = array(
  867. 'notify_announcements', 'notify_send_body',
  868. );
  869. $profile_ints = array(
  870. 'notify_regularity',
  871. 'notify_types',
  872. );
  873. $profile_floats = array(
  874. );
  875. $profile_strings = array(
  876. 'buddy_list',
  877. 'ignore_boards',
  878. );
  879. if (isset($_POST['sa']) && $_POST['sa'] == 'ignoreboards' && empty($_POST['ignore_brd']))
  880. $_POST['ignore_brd'] = array();
  881. unset($_POST['ignore_boards']); // Whatever it is set to is a dirty fithy thing. Kinda like our minds.
  882. if (isset($_POST['ignore_brd']))
  883. {
  884. if (!is_array($_POST['ignore_brd']))
  885. $_POST['ignore_brd'] = array ( $_POST['ignore_brd'] );
  886. foreach ($_POST['ignore_brd'] as $k => $d )
  887. {
  888. $d = (int) $d;
  889. if ($d != 0)
  890. $_POST['ignore_brd'][$k] = $d;
  891. else
  892. unset($_POST['ignore_brd'][$k]);
  893. }
  894. $_POST['ignore_boards'] = implode(',', $_POST['ignore_brd']);
  895. unset($_POST['ignore_brd']);
  896. }
  897. // Here's where we sort out all the 'other' values...
  898. if ($changeOther)
  899. {
  900. makeThemeChanges($memID, isset($_POST['id_theme']) ? (int) $_POST['id_theme'] : $old_profile['id_theme']);
  901. //makeAvatarChanges($memID, $post_errors);
  902. makeNotificationChanges($memID);
  903. if (!empty($_REQUEST['sa']))
  904. makeCustomFieldChanges($memID, $_REQUEST['sa'], false);
  905. foreach ($profile_bools as $var)
  906. if (isset($_POST[$var]))
  907. $profile_vars[$var] = empty($_POST[$var]) ? '0' : '1';
  908. foreach ($profile_ints as $var)
  909. if (isset($_POST[$var]))
  910. $profile_vars[$var] = $_POST[$var] != '' ? (int) $_POST[$var] : '';
  911. foreach ($profile_floats as $var)
  912. if (isset($_POST[$var]))
  913. $profile_vars[$var] = (float) $_POST[$var];
  914. foreach ($profile_strings as $var)
  915. if (isset($_POST[$var]))
  916. $profile_vars[$var] = $_POST[$var];
  917. }
  918. }
  919. // Make any theme changes that are sent with the profile..
  920. function makeThemeChanges($memID, $id_theme)
  921. {
  922. global $modSettings, $smcFunc, $context;
  923. $reservedVars = array(
  924. 'actual_theme_url',
  925. 'actual_images_url',
  926. 'base_theme_dir',
  927. 'base_theme_url',
  928. 'default_images_url',
  929. 'default_theme_dir',
  930. 'default_theme_url',
  931. 'default_template',
  932. 'images_url',
  933. 'number_recent_posts',
  934. 'smiley_sets_default',
  935. 'theme_dir',
  936. 'theme_id',
  937. 'theme_layers',
  938. 'theme_templates',
  939. 'theme_url',
  940. );
  941. // Can't change reserved vars.
  942. if ((isset($_POST['options']) && array_intersect($_POST['options'], $reservedVars) != array()) || (isset($_POST['default_options']) && array_intersect($_POST['default_options'], $reservedVars) != array()))
  943. fatal_lang_error('no_access', false);
  944. // Don't allow any overriding of custom fields with default or non-default options.
  945. $request = $smcFunc['db_query']('', '
  946. SELECT col_name
  947. FROM {db_prefix}custom_fields
  948. WHERE active = {int:is_active}',
  949. array(
  950. 'is_active' => 1,
  951. )
  952. );
  953. $custom_fields = array();
  954. while ($row = $smcFunc['db_fetch_assoc']($request))
  955. $custom_fields[] = $row['col_name'];
  956. $smcFunc['db_free_result']($request);
  957. // These are the theme changes...
  958. $themeSetArray = array();
  959. if (isset($_POST['options']) && is_array($_POST['options']))
  960. {
  961. foreach ($_POST['options'] as $opt => $val)
  962. {
  963. if (in_array($opt, $custom_fields))
  964. continue;
  965. // These need to be controlled.
  966. if ($opt == 'topics_per_page' || $opt == 'messages_per_page')
  967. $val = max(0, min($val, 50));
  968. $themeSetArray[] = array($memID, $id_theme, $opt, is_array($val) ? implode(',', $val) : $val);
  969. }
  970. }
  971. $erase_options = array();
  972. if (isset($_POST['default_options']) && is_array($_POST['default_options']))
  973. foreach ($_POST['default_options'] as $opt => $val)
  974. {
  975. if (in_array($opt, $custom_fields))
  976. continue;
  977. // These need to be controlled.
  978. if ($opt == 'topics_per_page' || $opt == 'messages_per_page')
  979. $val = max(0, min($val, 50));
  980. $themeSetArray[] = array($memID, 1, $opt, is_array($val) ? implode(',', $val) : $val);
  981. $erase_options[] = $opt;
  982. }
  983. // If themeSetArray isn't still empty, send it to the database.
  984. if (empty($context['password_auth_failed']))
  985. {
  986. if (!empty($themeSetArray))
  987. {
  988. $smcFunc['db_insert']('replace',
  989. '{db_prefix}themes',
  990. array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'),
  991. $themeSetArray,
  992. array('id_member', 'id_theme', 'variable')
  993. );
  994. }
  995. if (!empty($erase_options))
  996. {
  997. $smcFunc['db_query']('', '
  998. DELETE FROM {db_prefix}themes
  999. WHERE id_theme != {int:id_theme}
  1000. AND variable IN ({array_string:erase_variables})
  1001. AND id_member = {int:id_member}',
  1002. array(
  1003. 'id_theme' => 1,
  1004. 'id_member' => $memID,
  1005. 'erase_variables' => $erase_options
  1006. )
  1007. );
  1008. }
  1009. $themes = explode(',', $modSettings['knownThemes']);
  1010. foreach ($themes as $t)
  1011. cache_put_data('theme_settings-' . $t . ':' . $memID, null, 60);
  1012. }
  1013. }
  1014. // Make any notification changes that need to be made.
  1015. function makeNotificationChanges($memID)
  1016. {
  1017. global $smcFunc;
  1018. // Update the boards they are being notified on.
  1019. if (isset($_POST['edit_notify_boards']) && !empty($_POST['notify_boards']))
  1020. {
  1021. // Make sure only integers are deleted.
  1022. foreach ($_POST['notify_boards'] as $index => $id)
  1023. $_POST['notify_boards'][$index] = (int) $id;
  1024. // id_board = 0 is reserved for topic notifications.
  1025. $_POST['notify_boards'] = array_diff($_POST['notify_boards'], array(0));
  1026. $smcFunc['db_query']('', '
  1027. DELETE FROM {db_prefix}log_notify
  1028. WHERE id_board IN ({array_int:board_list})
  1029. AND id_member = {int:selected_member}',
  1030. array(
  1031. 'board_list' => $_POST['notify_boards'],
  1032. 'selected_member' => $memID,
  1033. )
  1034. );
  1035. }
  1036. // We are editing topic notifications......
  1037. elseif (isset($_POST['edit_notify_topics']) && !empty($_POST['notify_topics']))
  1038. {
  1039. foreach ($_POST['notify_topics'] as $index => $id)
  1040. $_POST['notify_topics'][$index] = (int) $id;
  1041. // Make sure there are no zeros left.
  1042. $_POST['notify_topics'] = array_diff($_POST['notify_topics'], array(0));
  1043. $smcFunc['db_query']('', '
  1044. DELETE FROM {db_prefix}log_notify
  1045. WHERE id_topic IN ({array_int:topic_list})
  1046. AND id_member = {int:selected_member}',
  1047. array(
  1048. 'topic_list' => $_POST['notify_topics'],
  1049. 'selected_member' => $memID,
  1050. )
  1051. );
  1052. }
  1053. }
  1054. // Save any changes to the custom profile fields...
  1055. function makeCustomFieldChanges($memID, $area, $sanitize = true)
  1056. {
  1057. global $context, $smcFunc, $user_profile, $user_info, $modSettings;
  1058. if ($sanitize && isset($_POST['customfield']))
  1059. $_POST['customfield'] = htmlspecialchars__recursive($_POST['customfield']);
  1060. $where = $area == 'register' ? 'show_reg != 0' : 'show_profile = {string:area}';
  1061. // Load the fields we are saving too - make sure we save valid data (etc).
  1062. $request = $smcFunc['db_query']('', '
  1063. SELECT col_name, field_name, field_desc, field_type, field_length, field_options, default_value, show_reg, mask, private
  1064. FROM {db_prefix}custom_fields
  1065. WHERE ' . $where . '
  1066. AND active = {int:is_active}',
  1067. array(
  1068. 'is_active' => 1,
  1069. 'area' => $area,
  1070. )
  1071. );
  1072. $changes = array();
  1073. $log_changes = array();
  1074. while ($row = $smcFunc['db_fetch_assoc']($request))
  1075. {
  1076. /* This means don't save if:
  1077. - The user is NOT an admin.
  1078. - The data is not freely viewable and editable by users.
  1079. - The data is not invisible to users but editable by the owner (or if it is the user is not the owner)
  1080. - The area isn't registration, and if it is that the field is not suppossed to be shown there.
  1081. */
  1082. if ($row['private'] != 0 && !allowedTo('admin_forum') && ($memID != $user_info['id'] || $row['private'] != 2) && ($area != 'register' || $row['show_reg'] == 0))
  1083. continue;
  1084. // Validate the user data.
  1085. if ($row['field_type'] == 'check')
  1086. $value = isset($_POST['customfield'][$row['col_name']]) ? 1 : 0;
  1087. elseif ($row['field_type'] == 'select' || $row['field_type'] == 'radio')
  1088. {
  1089. $value = $row['default_value'];
  1090. foreach (explode(',', $row['field_options']) as $k => $v)
  1091. if (isset($_POST['customfield'][$row['col_name']]) && $_POST['customfield'][$row['col_name']] == $k)
  1092. $value = $v;
  1093. }
  1094. // Otherwise some form of text!
  1095. else
  1096. {
  1097. $value = isset($_POST['customfield'][$row['col_name']]) ? $_POST['customfield'][$row['col_name']] : '';
  1098. if ($row['field_length'])
  1099. $value = $smcFunc['substr']($value, 0, $row['field_length']);
  1100. // Any masks?
  1101. if ($row['field_type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none')
  1102. {
  1103. //!!! We never error on this - just ignore it at the moment...
  1104. if ($row['mask'] == 'email' && (preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $value) === 0 || strlen($value) > 255))
  1105. $value = '';
  1106. elseif ($row['mask'] == 'number')
  1107. {
  1108. $value = (int) $value;
  1109. }
  1110. elseif (substr($row['mask'], 0, 5) == 'regex' && preg_match(substr($row['mask'], 5), $value) === 0)
  1111. $value = '';
  1112. }
  1113. }
  1114. // Did it change?
  1115. if (!isset($user_profile[$memID]['options'][$row['col_name']]) || $user_profile[$memID]['options'][$row['col_name']] != $value)
  1116. {
  1117. $log_changes[] = array(
  1118. 'action' => 'customfield_' . $row['col_name'],
  1119. 'id_log' => 2,
  1120. 'log_time' => time(),
  1121. 'id_member' => $memID,
  1122. 'ip' => $user_info['ip'],
  1123. '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'])),
  1124. );
  1125. $changes[] = array(1, $row['col_name'], $value, $memID);
  1126. $user_profile[$memID]['options'][$row['col_name']] = $value;
  1127. }
  1128. }
  1129. $smcFunc['db_free_result']($request);
  1130. // Make those changes!
  1131. if (!empty($changes) && empty($context['password_auth_failed']))
  1132. {
  1133. $smcFunc['db_insert']('replace',
  1134. '{db_prefix}themes',
  1135. array('id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534', 'id_member' => 'int'),
  1136. $changes,
  1137. array('id_theme', 'variable', 'id_member')
  1138. );
  1139. if (!empty($log_changes) && !empty($modSettings['modlog_enabled']))
  1140. $smcFunc['db_insert']('',
  1141. '{db_prefix}log_actions',
  1142. array(
  1143. 'action' => 'string', 'id_log' => 'int', 'log_time' => 'int', 'id_member' => 'int', 'ip' => 'string-16',
  1144. 'extra' => 'string-65534',
  1145. ),
  1146. $log_changes,
  1147. array('id_action')
  1148. );
  1149. }
  1150. }
  1151. // Show all the users buddies, as well as a add/delete interface.
  1152. function editBuddyIgnoreLists($memID)
  1153. {
  1154. global $sourcedir, $context, $txt, $scripturl, $modSettings, $user_profile;
  1155. // Do a quick check to ensure people aren't getting here illegally!
  1156. if (!$context['user']['is_owner'] || empty($modSettings['enable_buddylist']))
  1157. fatal_lang_error('no_access', false);
  1158. // Can we email the user direct?
  1159. $context['can_moderate_forum'] = allowedTo('moderate_forum');
  1160. $subActions = array(
  1161. 'buddies' => array('editBuddies', $txt['editBuddies']),
  1162. 'ignore' => array('editIgnoreList', $txt['editIgnoreList']),
  1163. );
  1164. $context['list_area'] = isset($_GET['sa']) && isset($subActions[$_GET['sa']]) ? $_GET['sa'] : 'buddies';
  1165. // Create the tabs for the template.
  1166. $context[$context['profile_menu_name']]['tab_data'] = array(
  1167. 'title' => $txt['editBuddyIgnoreLists'],
  1168. 'description' => $txt['buddy_ignore_desc'],
  1169. 'tabs' => array(
  1170. 'buddies' => array(),
  1171. 'ignore' => array(),
  1172. ),
  1173. );
  1174. // Pass on to the actual function.
  1175. $context['sub_template'] = $subActions[$context['list_area']][0];
  1176. $subActions[$context['list_area']][0]($memID);
  1177. }
  1178. // Show all the users buddies, as well as a add/delete interface.
  1179. function editBuddies($memID)
  1180. {
  1181. global $txt, $scripturl, $modSettings;
  1182. global $context, $user_profile, $memberContext, $smcFunc;
  1183. // For making changes!
  1184. $buddiesArray = explode(',', $user_profile[$memID]['buddy_list']);
  1185. foreach ($buddiesArray as $k => $dummy)
  1186. if ($dummy == '')
  1187. unset($buddiesArray[$k]);
  1188. // Removing a buddy?
  1189. if (isset($_GET['remove']))
  1190. {
  1191. // Heh, I'm lazy, do it the easy way...
  1192. foreach ($buddiesArray as $key => $buddy)
  1193. if ($buddy == (int) $_GET['remove'])
  1194. unset($buddiesArray[$key]);
  1195. // Make the changes.
  1196. $user_profile[$memID]['buddy_list'] = implode(',', $buddiesArray);
  1197. updateMemberData($memID, array('buddy_list' => $user_profile[$memID]['buddy_list']));
  1198. // Redirect off the page because we don't like all this ugly query stuff to stick in the history.
  1199. redirectexit('action=profile;area=lists;sa=buddies;u=' . $memID);
  1200. }
  1201. elseif (isset($_POST['new_buddy']))
  1202. {
  1203. // Prepare the string for extraction...
  1204. $_POST['new_buddy'] = strtr($smcFunc['htmlspecialchars']($_POST['new_buddy'], ENT_QUOTES), array('&quot;' => '"'));
  1205. preg_match_all('~"([^"]+)"~', $_POST['new_buddy'], $matches);
  1206. $new_buddies = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_POST['new_buddy']))));
  1207. foreach ($new_buddies as $k => $dummy)
  1208. {
  1209. $new_buddies[$k] = strtr(trim($new_buddies[$k]), array('\'' => '&#039;'));
  1210. if (strlen($new_buddies[$k]) == 0)
  1211. unset($new_buddies[$k]);
  1212. }
  1213. if (!empty($new_buddies))
  1214. {
  1215. // Now find out the id_member of the buddy.
  1216. $request = $smcFunc['db_query']('', '
  1217. SELECT id_member
  1218. FROM {db_prefix}members
  1219. WHERE member_name IN ({array_string:new_buddies}) OR real_name IN ({array_string:new_buddies})
  1220. LIMIT {int:count_new_buddies}',
  1221. array(
  1222. 'new_buddies' => $new_buddies,
  1223. 'count_new_buddies' => count($new_buddies),
  1224. )
  1225. );
  1226. // Add the new member to the buddies array.
  1227. while ($row = $smcFunc['db_fetch_assoc']($request))
  1228. $buddiesArray[] = (int) $row['id_member'];
  1229. $smcFunc['db_free_result']($request);
  1230. // Now update the current users buddy list.
  1231. $user_profile[$memID]['buddy_list'] = implode(',', $buddiesArray);
  1232. updateMemberData($memID, array('buddy_list' => $user_profile[$memID]['buddy_list']));
  1233. }
  1234. // Back to the buddy list!
  1235. redirectexit('action=profile;area=lists;sa=buddies;u=' . $memID);
  1236. }
  1237. // Get all the users "buddies"...
  1238. $buddies = array();
  1239. if (!empty($buddiesArray))
  1240. {
  1241. $result = $smcFunc['db_query']('', '
  1242. SELECT id_member
  1243. FROM {db_prefix}members
  1244. WHERE id_member IN ({array_int:buddy_list})
  1245. ORDER BY real_name
  1246. LIMIT {int:buddy_list_count}',
  1247. array(
  1248. 'buddy_list' => $buddiesArray,
  1249. 'buddy_list_count' => substr_count($user_profile[$memID]['buddy_list'], ',') + 1,
  1250. )
  1251. );
  1252. while ($row = $smcFunc['db_fetch_assoc']($result))
  1253. $buddies[] = $row['id_member'];
  1254. $smcFunc['db_free_result']($result);
  1255. }
  1256. $context['buddy_count'] = count($buddies);
  1257. // Load all the members up.
  1258. loadMemberData($buddies, false, 'profile');
  1259. // Setup the context for each buddy.
  1260. $context['buddies'] = array();
  1261. foreach ($buddies as $buddy)
  1262. {
  1263. loadMemberContext($buddy);
  1264. $context['buddies'][$buddy] = $memberContext[$buddy];
  1265. }
  1266. }
  1267. // Allows the user to view their ignore list, as well as the option to manage members on it.
  1268. function editIgnoreList($memID)
  1269. {
  1270. global $txt, $scripturl, $modSettings;
  1271. global $context, $user_profile, $memberContext, $smcFunc;
  1272. // For making changes!
  1273. $ignoreArray = explode(',', $user_profile[$memID]['pm_ignore_list']);
  1274. foreach ($ignoreArray as $k => $dummy)
  1275. if ($dummy == '')
  1276. unset($ignoreArray[$k]);
  1277. // Removing a member from the ignore list?
  1278. if (isset($_GET['remove']))
  1279. {
  1280. // Heh, I'm lazy, do it the easy way...
  1281. foreach ($ignoreArray as $key => $id_remove)
  1282. if ($id_remove == (int) $_GET['remove'])
  1283. unset($ignoreArray[$key]);
  1284. // Make the changes.
  1285. $user_profile[$memID]['pm_ignore_list'] = implode(',', $ignoreArray);
  1286. updateMemberData($memID, array('pm_ignore_list' => $user_profile[$memID]['pm_ignore_list']));
  1287. // Redirect off the page because we don't like all …

Large files files are truncated, but you can click here to view the full file