PageRenderTime 94ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/SpecialUserFuncs.php

https://code.google.com/p/enanocms/
PHP | 2024 lines | 1683 code | 188 blank | 153 comment | 318 complexity | 51091260df86325b41b25fcd57f04394 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**!info**
  3. {
  4. "Plugin Name" : "plugin_specialuserfuncs_title",
  5. "Plugin URI" : "http://enanocms.org/",
  6. "Description" : "plugin_specialuserfuncs_desc",
  7. "Author" : "Dan Fuhry",
  8. "Version" : "1.1.6",
  9. "Author URI" : "http://enanocms.org/"
  10. }
  11. **!*/
  12. /*
  13. * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
  14. * Copyright (C) 2006-2009 Dan Fuhry
  15. *
  16. * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  17. * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  20. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
  21. */
  22. global $db, $session, $paths, $template, $plugins; // Common objects
  23. // $plugins->attachHook('session_started', 'SpecialUserFuncs_paths_init();');
  24. function SpecialUserFuncs_paths_init()
  25. {
  26. register_special_page('Login', 'specialpage_log_in');
  27. register_special_page('Logout', 'specialpage_log_out');
  28. register_special_page('Register', 'specialpage_register');
  29. register_special_page('Preferences', 'specialpage_preferences');
  30. register_special_page('Contributions', 'specialpage_contributions');
  31. register_special_page('ChangeStyle', 'specialpage_change_theme');
  32. register_special_page('ActivateAccount', 'specialpage_activate_account');
  33. register_special_page('Captcha', 'specialpage_captcha');
  34. register_special_page('PasswordReset', 'specialpage_password_reset');
  35. register_special_page('Memberlist', 'specialpage_member_list');
  36. register_special_page('LangExportJSON', 'specialpage_language_export', false);
  37. register_special_page('Avatar', 'specialpage_avatar', false);
  38. }
  39. // function names are IMPORTANT!!! The name pattern is: page_<namespace ID>_<page URLname, without namespace>
  40. $__login_status = '';
  41. function page_Special_Login()
  42. {
  43. global $db, $session, $paths, $template, $plugins; // Common objects
  44. global $login_result;
  45. global $lang, $output;
  46. // Determine which level we're going up to
  47. $level = ( isset($_GET['level']) && in_array($_GET['level'], array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') ) ) ? intval($_GET['level']) : USER_LEVEL_MEMBER;
  48. if ( isset($_POST['login']) )
  49. {
  50. if ( in_array($_POST['level'], array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') ) )
  51. {
  52. $level = intval($_POST['level']);
  53. }
  54. }
  55. // Don't allow going from guest straight to elevated
  56. // FIXME do we want to allow this with a CSRF check?
  57. if ( $level > USER_LEVEL_MEMBER && !$session->user_logged_in )
  58. {
  59. $level = USER_LEVEL_MEMBER;
  60. }
  61. // If we're already at or above this level, redirect to the target page or, if no target
  62. // specified, back to the main page.
  63. if ( $level <= USER_LEVEL_MEMBER && $session->user_logged_in )
  64. {
  65. if ( $target = $paths->getAllParams() )
  66. {
  67. redirect(makeUrl($target), '', '', 0);
  68. }
  69. $paths->main_page();
  70. }
  71. // Lockout aliasing
  72. $lockout =& $login_result['lockout'];
  73. $output->header();
  74. echo '<form action="' . makeUrl($paths->nslist['Special'].'Login') . '" method="post" name="loginform" onsubmit="try { return runEncryption(); } catch(e) { console.error(e); };">';
  75. if ( $p = $paths->getAllParams() )
  76. {
  77. echo '<input type="hidden" name="return_to" value="' . htmlspecialchars($p) . '" />';
  78. }
  79. else if ( isset($_POST['login']) && isset($_POST['return_to']) )
  80. {
  81. echo '<input type="hidden" name="return_to" value="' . htmlspecialchars($_POST['return_to']) . '" />';
  82. }
  83. // determine what the "remember me" checkbox should say
  84. $session_time = intval(getConfig('session_remember_time', '30'));
  85. if ( $session_time === 0 )
  86. {
  87. // sessions are infinite
  88. $text_remember = $lang->get('user_login_check_remember_infinite');
  89. }
  90. else
  91. {
  92. // is the number of days evenly divisible by 7? if so, use weeks
  93. if ( $session_time % 7 == 0 )
  94. {
  95. $session_time = $session_time / 7;
  96. $unit = 'week';
  97. }
  98. else
  99. {
  100. $unit = 'day';
  101. }
  102. // if it's not equal to 1, pluralize it
  103. if ( $session_time != 1 )
  104. {
  105. $unit .= $lang->get('meta_plural');
  106. }
  107. $text_remember = $lang->get('user_login_check_remember', array(
  108. 'session_length' => $session_time,
  109. 'length_units' => $lang->get("etc_unit_$unit")
  110. ));
  111. }
  112. if ( $error_text = login_get_error($login_result) )
  113. {
  114. echo '<div class="error-box-mini">' . htmlspecialchars($error_text) . '</div>';
  115. }
  116. //
  117. // START FORM
  118. //
  119. ?>
  120. <div class="tblholder">
  121. <table border="0" style="width: 100%;" cellspacing="1" cellpadding="4">
  122. <tr>
  123. <th colspan="3">
  124. <!-- Table header: "Please enter..." -->
  125. <?php echo ( $level > USER_LEVEL_MEMBER ) ? $lang->get('user_login_message_short_elev') : $lang->get('user_login_message_short'); ?>
  126. </th>
  127. </tr>
  128. <tr>
  129. <td colspan="3" class="row1">
  130. <!-- Introduction text -->
  131. <?php
  132. if ( $level <= USER_LEVEL_MEMBER )
  133. echo '<p>' . $lang->get('user_login_body', array('reg_link' => makeUrlNS('Special', 'Register'))) . '</p>';
  134. else
  135. echo '<p>' . $lang->get('user_login_body_elev') . '</p>';
  136. ?>
  137. </td>
  138. </tr>
  139. <tr>
  140. <!-- Username field -->
  141. <td class="row2">
  142. <?php echo $lang->get('user_login_field_username'); ?>:
  143. </td>
  144. <td class="row1">
  145. <input name="username" size="25" type="text" value="<?php echo $session->user_logged_in ? htmlspecialchars($session->username) : ''; ?>" />
  146. </td>
  147. <?php if ( $level <= USER_LEVEL_MEMBER ): ?>
  148. <!-- Forgot password / create account links -->
  149. <td rowspan="<?php echo ( ( $lockout['active'] && $lockout['policy'] == 'captcha' ) ) ? '4' : '2'; ?>" class="row3">
  150. <small><?php echo $lang->get('user_login_forgotpass_blurb', array('forgotpass_link' => makeUrlNS('Special', 'PasswordReset'))); ?><br />
  151. <?php echo $lang->get('user_login_createaccount_blurb', array('reg_link' => makeUrlNS('Special', 'Register'))); ?></small>
  152. </td>
  153. <?php endif; ?>
  154. </tr>
  155. <tr>
  156. <!-- Password field -->
  157. <td class="row2">
  158. <?php echo $lang->get('user_login_field_password'); ?>:
  159. </td><td class="row1"><input name="password" size="25" type="password" /></td>
  160. </tr>
  161. <?php
  162. // CAPTCHA?
  163. if ( $lockout['active'] && $lockout['policy'] == 'captcha' )
  164. {
  165. ?>
  166. <!-- CAPTCHA -->
  167. <tr>
  168. <td class="row2" rowspan="2">
  169. <?php echo $lang->get('user_login_field_captcha'); ?>:
  170. <br />
  171. </td>
  172. <td class="row1">
  173. <input type="hidden" name="captcha_hash" value="<?php echo $lockout['captcha']; ?>" />
  174. <input name="captcha_code" size="25" type="text" tabindex="<?php echo ( $level <= USER_LEVEL_MEMBER ) ? '3' : '4'; ?>" />
  175. </td>
  176. </tr>
  177. <tr>
  178. <td class="row3">
  179. <img src="<?php echo makeUrlNS('Special', 'Captcha/' . $lockout['captcha']) ?>" onclick="this.src=this.src+'/a';" style="cursor: pointer;" />
  180. </td>
  181. </tr>
  182. <?php
  183. }
  184. // Run hooks
  185. $code = $plugins->setHook('login_form_html');
  186. foreach ( $code as $cmd )
  187. {
  188. eval($cmd);
  189. }
  190. // level-2 only: "Remember me" switch
  191. if ( $level <= USER_LEVEL_MEMBER )
  192. {
  193. ?>
  194. <tr>
  195. <td class="row2">
  196. <?php echo $lang->get('user_login_field_remember'); ?>
  197. </td>
  198. <td class="row1" colspan="2">
  199. <label>
  200. <input type="checkbox" name="remember" tabindex="3" />
  201. <?php echo $text_remember; ?>
  202. </label>
  203. </td>
  204. </tr>
  205. <!-- Crypto notice -->
  206. <?php
  207. }
  208. // lol DeMorgan'd
  209. $crypto_disable = ( isset($_GET['use_crypt']) && $_GET['use_crypt'] == '0' );
  210. // Crypto disable: crypto on, normal login
  211. if ( $level <= USER_LEVEL_MEMBER && !$crypto_disable )
  212. {
  213. echo '<tr>
  214. <td class="row3" colspan="3">';
  215. $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
  216. $nocrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=0", true);
  217. echo '<p><b>' . $lang->get('user_login_nocrypt_title') . '</b> ' . $lang->get('user_login_nocrypt_body', array('nocrypt_link' => $nocrypt_link)) . '</p>';
  218. echo '<p>' . $lang->get('user_login_nocrypt_countrylist') . '</p>';
  219. echo ' </td>
  220. </tr>';
  221. }
  222. // Crypto disable: crypto OFF, normal login
  223. else if ( $level <= USER_LEVEL_MEMBER && $crypto_disable )
  224. {
  225. echo '<tr>
  226. <td class="row3" colspan="3">';
  227. $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
  228. $usecrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=1", true);
  229. echo '<p><b>' . $lang->get('user_login_usecrypt_title') . '</b> ' . $lang->get('user_login_usecrypt_body', array('usecrypt_link' => $usecrypt_link)) . '</p>';
  230. echo '<p>' . $lang->get('user_login_usecrypt_countrylist') . '</p>';
  231. echo ' </td>
  232. </tr>';
  233. }
  234. // Crypto disable: crypto on, ELEV login
  235. else if ( $level > USER_LEVEL_MEMBER && $GLOBALS['dh_supported'] )
  236. {
  237. echo '<tr>';
  238. echo '<td class="row3" colspan="3">';
  239. echo '<p>' . $lang->get('user_login_dh_notice') . '</p>';
  240. echo '</td>';
  241. echo '</tr>';
  242. }
  243. ?>
  244. <!-- Submit button -->
  245. <tr>
  246. <th colspan="3" style="text-align: center" class="subhead">
  247. <input type="hidden" name="login" value="true" />
  248. <input type="submit" value="<?php echo $lang->get('user_login_btn_log_in'); ?>" />
  249. </th>
  250. </tr>
  251. </table>
  252. </div>
  253. <input type="hidden" name="level" value="<?php echo (string)$level; ?>" />
  254. <?php if ( $level <= USER_LEVEL_MEMBER ): ?>
  255. <script type="text/javascript">
  256. document.forms.loginform.username.focus();
  257. </script>
  258. <?php else: ?>
  259. <script type="text/javascript">
  260. document.forms.loginform.password.focus();
  261. </script>
  262. <?php endif; ?>
  263. <?php
  264. echo $session->generate_aes_form();
  265. // Any additional parameters that need to be passed back?
  266. if ( $p = $paths->getAllParams() )
  267. {
  268. // ... only if we have a return_to destination.
  269. $get_fwd = $_GET;
  270. unset($get_fwd['do']);
  271. if ( isset($get_fwd['target_do']) )
  272. {
  273. $get_fwd['do'] = $get_fwd['target_do'];
  274. unset($get_fwd['target_do']);
  275. }
  276. if ( isset($get_fwd['level']) )
  277. unset($get_fwd['level']);
  278. if ( isset($get_fwd['title']) )
  279. unset($get_fwd['title']);
  280. if ( !empty($get_fwd) )
  281. {
  282. $get_string = htmlspecialchars(enano_json_encode($get_fwd));
  283. echo '<input type="hidden" name="get_fwd" value="' . $get_string . '" />';
  284. }
  285. }
  286. else if ( isset($_POST['get_fwd']) )
  287. {
  288. echo '<input type="hidden" name="get_fwd" value="' . htmlspecialchars($_POST['get_fwd']) . '" />';
  289. }
  290. ?>
  291. </form>
  292. <?php
  293. if ( !$crypto_disable )
  294. echo $session->aes_javascript('loginform', 'password');
  295. ?>
  296. <?php
  297. $output->footer();
  298. }
  299. function page_Special_Login_preloader() // adding _preloader to the end of the function name calls the function before $session and $paths setup routines are called
  300. {
  301. global $db, $session, $paths, $template, $plugins; // Common objects
  302. global $login_result;
  303. global $lang;
  304. // Are we calling the JSON interface?
  305. $paths->fullpage = $GLOBALS['urlname'];
  306. if ( $paths->getParam(0) === 'action.json' )
  307. {
  308. if ( !isset($_POST['r']) )
  309. die('No request.');
  310. $request = $_POST['r'];
  311. try
  312. {
  313. $request = enano_json_decode($request);
  314. }
  315. catch ( Exception $e )
  316. {
  317. die(enano_json_encode(array(
  318. 'mode' => 'error',
  319. 'error' => 'ERR_JSON_PARSE_FAILED'
  320. )));
  321. }
  322. echo enano_json_encode($session->process_login_request($request));
  323. $db->close();
  324. exit;
  325. }
  326. // No. Process incoming results from the HTML version.
  327. if ( isset($_POST['login']) )
  328. {
  329. $_POST['password'] = $session->get_aes_post();
  330. $result = $session->process_login_request(array(
  331. 'mode' => 'login_pt',
  332. 'userinfo' => $_POST,
  333. 'level' => $_POST['level'],
  334. 'captcha_hash' => isset($_POST['captcha_hash']) ? $_POST['captcha_hash'] : false,
  335. 'captcha_code' => isset($_POST['captcha_code']) ? $_POST['captcha_code'] : false
  336. ));
  337. if ( $result['mode'] === 'login_success' )
  338. {
  339. //
  340. // LOGIN SUCCESS.
  341. // Redirect as necessary.
  342. //
  343. // Load our preferences
  344. $session->start();
  345. // Decode get_add
  346. $get_add = false;
  347. if ( isset($_POST['get_fwd']) )
  348. {
  349. try
  350. {
  351. $get_fwd = enano_json_decode($_POST['get_fwd']);
  352. $get_add = '';
  353. foreach ( $get_fwd as $key => $value )
  354. {
  355. if ( $key != 'auth' )
  356. $get_add .= "&{$key}=" . urlencode($value);
  357. }
  358. $get_add = ltrim($get_add, '&');
  359. }
  360. catch ( Exception $e )
  361. {
  362. }
  363. }
  364. // Going to a user-specified page?
  365. if ( isset($_POST['return_to']) )
  366. {
  367. // yea
  368. $name = get_page_title($_POST['return_to']);
  369. $subst = array(
  370. 'username' => $session->username,
  371. 'redir_target' => htmlspecialchars($name)
  372. );
  373. redirect( makeUrl($_POST['return_to'], $get_add), $lang->get('user_login_success_title'), $lang->get('user_login_success_body', $subst) );
  374. }
  375. else
  376. {
  377. // No, redirect them to the main page
  378. $subst = array(
  379. 'username' => $session->username,
  380. 'redir_target' => $lang->get('user_login_success_body_mainpage')
  381. );
  382. redirect( makeUrl(get_main_page(), $get_add), $lang->get('user_login_success_title'), $lang->get('user_login_success_body', $subst) );
  383. }
  384. }
  385. else if ( $result['mode'] === 'login_success_reset' )
  386. {
  387. // They logged in with a temporary password; send them to the reset form
  388. redirect($result['redirect_url'], '', '', 0);
  389. }
  390. // Otherwise, the result is likely an error.
  391. $login_result = $result;
  392. }
  393. else
  394. {
  395. $login_result = $session->process_login_request(array(
  396. 'mode' => 'getkey'
  397. ));
  398. }
  399. // This is a bit of a hack. The login form generates AES and DiffieHellman keys on its
  400. // own, so we need to clean up the ones from the login request API.
  401. if ( !empty($login_result['crypto']) )
  402. {
  403. $session->process_login_request(array(
  404. 'mode' => 'clean_key',
  405. 'key_aes' => $login_result['crypto']['aes_key'],
  406. 'key_dh' => $login_result['crypto']['dh_public_key'],
  407. ));
  408. }
  409. }
  410. /**
  411. * Given a Login API response, find the appropriate error text, if any.
  412. * @param array LoginAPI response
  413. * @return mixed Error string, or bool(false) if no error.
  414. */
  415. function login_get_error($response)
  416. {
  417. global $lang;
  418. if ( !empty($response['lockout']) )
  419. {
  420. // set this pluralality thing
  421. $response['lockout']['plural'] = $response['lockout']['time_rem'] == 1 ? '' : $lang->get('meta_plural');
  422. }
  423. if ( $response['mode'] == 'initial' )
  424. {
  425. // Just showing the box for the first time. If there's an error now, it's based on a preexisting lockout.
  426. if ( $response['lockout']['active'] )
  427. {
  428. return $lang->get('user_err_locked_out_initial_' . $response['lockout']['policy'], $response['lockout']);
  429. }
  430. return false;
  431. }
  432. else
  433. {
  434. // An attempt was made.
  435. switch($response['mode'])
  436. {
  437. case 'login_failure':
  438. // Generic login user error.
  439. $error = '';
  440. if ( ($x = $lang->get($response['error'])) != $response['error'] )
  441. $error = $x;
  442. else
  443. $error = $lang->get('user_err_' . $response['error']);
  444. if ( $response['lockout']['active'] && $response['lockout']['policy'] == 'lockout' )
  445. {
  446. // Lockout enforcement was just activated.
  447. return $lang->get('user_err_locked_out_initial_' . $response['lockout']['policy'], $response['lockout']);
  448. }
  449. else if ( $response['lockout']['policy'] != 'disable' && !$response['lockout']['active'] && $response['lockout']['fails'] > 0 )
  450. {
  451. // Lockout is in a warning state.
  452. $error .= ' ' . $lang->get('user_err_invalid_credentials_' . $response['lockout']['policy'], $response['lockout']);
  453. }
  454. return $error;
  455. break;
  456. case 'api_error':
  457. // Error in the API.
  458. return $lang->get('user_err_login_generic_title') + ': ' + $lang->get('user_' . strtolower($response['error']));
  459. break;
  460. }
  461. }
  462. return is_string($response['error']) ? $response['error'] : false;
  463. }
  464. function page_Special_Logout()
  465. {
  466. global $db, $session, $paths, $template, $plugins; // Common objects
  467. global $lang;
  468. if ( !$session->user_logged_in )
  469. $paths->main_page();
  470. $token = $paths->getParam(0);
  471. if ( $token !== $session->csrf_token )
  472. {
  473. csrf_request_confirm();
  474. }
  475. $l = $session->logout();
  476. if ( $l == 'success' )
  477. {
  478. $url = makeUrl(get_main_page(), false, true);
  479. if ( $paths->getParam(1) )
  480. {
  481. $pi = explode('/', $paths->getAllParams());
  482. $pi = implode('/', array_values(array_slice($pi, 1)));
  483. list($pid, $ns) = RenderMan::strToPageID($pi);
  484. $perms = $session->fetch_page_acl($pid, $ns);
  485. if ( $perms->get_permissions('read') )
  486. {
  487. $url = makeUrl($pi, false, true);
  488. }
  489. }
  490. redirect($url, $lang->get('user_logout_success_title'), $lang->get('user_logout_success_body'), 3);
  491. }
  492. $template->header();
  493. echo '<h3>' . $lang->get('user_logout_err_title') . '</h3>';
  494. echo '<p>' . $l . '</p>';
  495. $template->footer();
  496. }
  497. function page_Special_Register()
  498. {
  499. global $db, $session, $paths, $template, $plugins; // Common objects
  500. global $lang;
  501. // block registration except for guests and admins
  502. if ( $session->user_level < USER_LEVEL_ADMIN && $session->user_logged_in )
  503. {
  504. $paths->main_page();
  505. }
  506. // form field trackers
  507. $username = '';
  508. $email = '';
  509. $realname = '';
  510. $terms = getConfig('register_tou');
  511. if ( getConfig('account_activation') == 'disable' && $session->user_level < USER_LEVEL_ADMIN )
  512. {
  513. die_friendly($lang->get('user_reg_err_disabled_title'), '<p>' . $lang->get('user_reg_err_disabled_body') . '</p>');
  514. }
  515. // are we locked out from logging in? if so, also lock out registration
  516. if ( getConfig('lockout_policy') === 'lockout' )
  517. {
  518. $ip = $db->escape($_SERVER['REMOTE_ADDR']);
  519. $threshold = time() - ( 60 * intval(getConfig('lockout_duration')) );
  520. $limit = intval(getConfig('lockout_threshold'));
  521. $q = $db->sql_query('SELECT * FROM ' . table_prefix . "lockout WHERE timestamp >= $threshold ORDER BY timestamp DESC;");
  522. if ( !$q )
  523. $db->_die();
  524. if ( $db->numrows() >= $limit )
  525. {
  526. $row = $db->fetchrow();
  527. $db->free_result();
  528. $time_rem = intval(getConfig('lockout_duration')) - round((time() - $row['timestamp']) / 60);
  529. die_friendly($lang->get('user_reg_err_disabled_title'), '<p>' . $lang->get('user_reg_err_locked_out', array('time' => $time_rem)) . '</p>');
  530. }
  531. $db->free_result();
  532. }
  533. if(isset($_POST['submit']))
  534. {
  535. $_GET['coppa'] = ( isset($_POST['coppa']) ) ? $_POST['coppa'] : 'x';
  536. if ( $session->user_level < USER_LEVEL_ADMIN )
  537. {
  538. $captcharesult = $session->get_captcha($_POST['captchahash']);
  539. $session->kill_captcha();
  540. }
  541. // bypass captcha if logged in (at this point, if logged in, we're admin)
  542. if ( !$session->user_logged_in && strtolower($captcharesult) != strtolower($_POST['captchacode']) )
  543. {
  544. $s = $lang->get('user_reg_err_captcha');
  545. }
  546. else
  547. {
  548. if ( getConfig('enable_coppa') == '1' && ( !isset($_POST['coppa']) || ( isset($_POST['coppa']) && !in_array($_POST['coppa'], array('yes', 'no')) ) ) )
  549. {
  550. $s = 'Invalid COPPA input';
  551. }
  552. else if ( !$session->user_logged_in && !empty($terms) && !isset($_POST['tou_agreed']) )
  553. {
  554. $s = $lang->get('user_reg_err_accept_tou');
  555. }
  556. else
  557. {
  558. $coppa = ( isset($_POST['coppa']) && $_POST['coppa'] == 'yes' );
  559. $s = false;
  560. // decrypt password
  561. // as with the change pass form, we aren't going to bother checking the confirmation code because if the passwords didn't match
  562. // and yet the password got encrypted, that means the user screwed with the code, and if the user screwed with the code and thus
  563. // forgot his password, that's his problem.
  564. if ( $_POST['use_crypt'] == 'yes' )
  565. {
  566. $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
  567. $crypt_key = $session->fetch_public_key($_POST['crypt_key']);
  568. if ( !$crypt_key )
  569. {
  570. $s = $lang->get('user_reg_err_missing_key');
  571. }
  572. else
  573. {
  574. $data = $_POST['crypt_data'];
  575. $bin_key = hexdecode($crypt_key);
  576. //die("Decrypting with params: key $crypt_key, data $data");
  577. $password = $aes->decrypt($data, $bin_key, ENC_HEX);
  578. }
  579. }
  580. else
  581. {
  582. $password = $_POST['password'];
  583. }
  584. $error =& $s;
  585. /**
  586. * Validation of POST data coming from registration. Put an error message in the variable $error to stop registration.
  587. * @hook ucp_register_validate
  588. */
  589. $code = $plugins->setHook('ucp_register_validate');
  590. foreach ( $code as $cmd )
  591. {
  592. eval($cmd);
  593. }
  594. // All things verified, create account
  595. if ( !$s )
  596. $s = $session->create_user($_POST['username'], $password, $_POST['email'], $_POST['real_name'], $coppa);
  597. }
  598. }
  599. if($s == 'success' && !$coppa)
  600. {
  601. switch(getConfig('account_activation'))
  602. {
  603. case "none":
  604. default:
  605. $str = $lang->get('user_reg_msg_success_activ_none', array('login_link' => makeUrlNS('Special', 'Login', false, true)));
  606. break;
  607. case "user":
  608. $str = $lang->get('user_reg_msg_success_activ_user');
  609. break;
  610. case "admin":
  611. $str = $lang->get('user_reg_msg_success_activ_admin');
  612. break;
  613. }
  614. die_friendly($lang->get('user_reg_msg_success_title'), '<p>' . $lang->get('user_reg_msg_success_body') . ' ' . $str . '</p>');
  615. }
  616. else if ( $s == 'success' && $coppa )
  617. {
  618. $str = $lang->get('user_reg_msg_success_activ_coppa');
  619. die_friendly($lang->get('user_reg_msg_success_title'), '<p>' . $lang->get('user_reg_msg_success_body') . ' ' . $str . '</p>');
  620. }
  621. $username = htmlspecialchars($_POST['username']);
  622. $email = htmlspecialchars($_POST['email']);
  623. $realname = htmlspecialchars($_POST['real_name']);
  624. }
  625. $template->header();
  626. echo $lang->get('user_reg_msg_greatercontrol');
  627. if ( getConfig('account_activation') == 'disable' && $session->user_level >= USER_LEVEL_ADMIN )
  628. {
  629. echo '<div class="info-box">' . $lang->get('user_reg_msg_admin_forced') . '</div>';
  630. }
  631. if ( getConfig('enable_coppa') != '1' || ( isset($_GET['coppa']) && in_array($_GET['coppa'], array('yes', 'no')) ) )
  632. {
  633. $coppa = ( isset($_GET['coppa']) && $_GET['coppa'] == 'yes' );
  634. $session->kill_captcha();
  635. $captchacode = $session->make_captcha();
  636. $pubkey = $session->rijndael_genkey();
  637. $challenge = $session->dss_rand();
  638. ?>
  639. <h3><?php echo $lang->get('user_reg_msg_table_title'); ?></h3>
  640. <form name="regform" action="<?php echo makeUrl($paths->page); ?>" method="post" onsubmit="return runEncryption();">
  641. <div class="tblholder">
  642. <table border="0" width="100%" cellspacing="1" cellpadding="4">
  643. <tr><th colspan="3"><?php echo $lang->get('user_reg_msg_table_subtitle'); ?></th></tr>
  644. <?php if(isset($_POST['submit'])) echo '<tr><td colspan="3" class="row2" style="color: red;">'.$s.'</td></tr>'; ?>
  645. <!-- FIELD: Username -->
  646. <tr>
  647. <td class="row1" style="width: 50%;">
  648. <?php echo $lang->get('user_reg_lbl_field_username'); ?>
  649. <span id="e_username"></span>
  650. </td>
  651. <td class="row1" style="width: 50%;">
  652. <input tabindex="1" type="text" name="username" size="30" value="<?php echo $username; ?>" onkeyup="namegood = false; validateForm(this);" onblur="checkUsername();" />
  653. </td>
  654. <td class="row1" style="width: 1px;">
  655. <img alt="Good/bad icon" src="<?php echo scriptPath; ?>/images/checkbad.png" id="s_username" />
  656. </td>
  657. </tr>
  658. <!-- FIELD: Password -->
  659. <tr>
  660. <td class="row3" style="width: 50%;" rowspan="<?php echo ( getConfig('pw_strength_enable') == '1' ) ? '3' : '2'; ?>">
  661. <?php echo $lang->get('user_reg_lbl_field_password'); ?>
  662. <span id="e_password"></span>
  663. <?php if ( getConfig('pw_strength_enable') == '1' && getConfig('pw_strength_minimum') > -10 ): ?>
  664. <small><?php echo $lang->get('user_reg_msg_password_score'); ?></small>
  665. <?php endif; ?>
  666. </td>
  667. <td class="row3" style="width: 50%;">
  668. <input tabindex="2" type="password" name="password" size="15" onkeyup="<?php if ( getConfig('pw_strength_enable') == '1' ): ?>password_score_field(this); <?php endif; ?>validateForm(this);" /><?php if ( getConfig('pw_strength_enable') == '1' ): ?><span class="password-checker" style="font-weight: bold; color: #aaaaaa;"> Loading...</span><?php endif; ?>
  669. </td>
  670. <td rowspan="<?php echo ( getConfig('pw_strength_enable') == '1' ) ? '3' : '2'; ?>" class="row3" style="max-width: 24px;">
  671. <img alt="Good/bad icon" src="<?php echo scriptPath; ?>/images/checkbad.png" id="s_password" />
  672. </td>
  673. </tr>
  674. <!-- FIELD: Password confirmation -->
  675. <tr>
  676. <td class="row3" style="width: 50%;">
  677. <input tabindex="3" type="password" name="password_confirm" size="15" onkeyup="validateForm(this);" /> <small><?php echo $lang->get('user_reg_lbl_field_password_confirm'); ?></small>
  678. </td>
  679. </tr>
  680. <!-- FIELD: Password strength meter -->
  681. <?php if ( getConfig('pw_strength_enable') == '1' ): ?>
  682. <tr>
  683. <td class="row3" style="width: 50%;">
  684. <div id="pwmeter"></div>
  685. </td>
  686. </tr>
  687. <?php endif; ?>
  688. <!-- FIELD: E-mail address -->
  689. <tr>
  690. <td class="row1" style="width: 50%;">
  691. <?php
  692. if ( $coppa )
  693. {
  694. echo $lang->get('user_reg_lbl_field_email_coppa');
  695. }
  696. else
  697. {
  698. echo $lang->get('user_reg_lbl_field_email');
  699. }
  700. ?>
  701. <?php
  702. if ( ( $x = getConfig('account_activation') ) == 'user' )
  703. {
  704. echo '<br /><small>' . $lang->get('user_reg_msg_email_activuser') . '</small>';
  705. }
  706. ?>
  707. </td>
  708. <td class="row1" style="width: 50%;">
  709. <input tabindex="4" type="text" name="email" size="30" value="<?php echo $email; ?>" onkeyup="validateForm(this);" />
  710. </td>
  711. <td class="row1" style="max-width: 24px;">
  712. <img alt="Good/bad icon" src="<?php echo scriptPath; ?>/images/checkbad.png" id="s_email" />
  713. </td>
  714. </tr>
  715. <!-- FIELD: Real name -->
  716. <tr>
  717. <td class="row3" style="width: 50%;">
  718. <?php echo $lang->get('user_reg_lbl_field_realname'); ?><br />
  719. <small><?php echo $lang->get('user_reg_msg_realname_optional'); ?></small>
  720. </td>
  721. <td class="row3" style="width: 50%;">
  722. <input tabindex="5" type="text" name="real_name" size="30" value="<?php echo $realname; ?>" />
  723. </td>
  724. <td class="row3" style="max-width: 24px;">
  725. </td>
  726. </tr>
  727. <?php
  728. /**
  729. * Allows adding fields to the user registration form. Form is built with Enano tables, 3 columns. (Rightmost can be left empty or if you're using Javascript validation an image you can update with your own Javascript code)
  730. * @hook ucp_register_form
  731. */
  732. $code = $plugins->setHook('ucp_register_form');
  733. foreach ( $code as $cmd )
  734. {
  735. eval($cmd);
  736. }
  737. ?>
  738. <!-- FIELD: CAPTCHA image -->
  739. <?php
  740. if ( !$session->user_logged_in ):
  741. ?>
  742. <tr>
  743. <td class="row1" style="width: 50%;" rowspan="2">
  744. <?php echo $lang->get('user_reg_lbl_field_captcha'); ?><br />
  745. <small>
  746. <?php echo $lang->get('user_reg_msg_captcha_pleaseenter', array('regen_flags' => 'href="#" onclick="regenCaptcha(); return false;"')); ?><br />
  747. <br />
  748. <?php echo $lang->get('user_reg_msg_captcha_blind'); ?>
  749. </small>
  750. </td>
  751. <td class="row1">
  752. <img id="captchaimg" alt="CAPTCHA image" src="<?php echo makeUrlNS('Special', 'Captcha/'.$captchacode); ?>" style="cursor: pointer;" onclick="regenCaptcha(); return false;" />
  753. </td>
  754. <td class="row1">
  755. <img alt="Good/bad icon" src="<?php echo scriptPath; ?>/images/checkbad.png" id="s_captcha" />
  756. </td>
  757. </tr>
  758. <!-- FIELD: CAPTCHA input field -->
  759. <tr>
  760. <td class="row1" colspan="2">
  761. <?php echo $lang->get('user_reg_lbl_field_captcha_code'); ?>
  762. <input tabindex="6" name="captchacode" type="text" size="10" onkeyup="validateCaptcha(this);" />
  763. <img id="captchaajax" width="16" height="16" src="<?php echo cdnPath; ?>/images/spacer.gif" />
  764. <input type="hidden" name="captchahash" value="<?php echo $captchacode; ?>" />
  765. </td>
  766. </tr>
  767. <!-- FIELD: TOU -->
  768. <?php
  769. if ( !empty($terms) ):
  770. ?>
  771. <tr>
  772. <td class="row1" colspan="3">
  773. <?php
  774. echo $lang->get('user_reg_msg_please_read_tou');
  775. ?>
  776. </td>
  777. </tr>
  778. <tr>
  779. <td class="row3" colspan="3">
  780. <div style="border: 1px solid #000000; height: 75px; width: 60%; clip: rect(0px,auto,auto,0px); overflow: auto; background-color: #FFF; margin: 0 auto; padding: 4px;">
  781. <?php
  782. echo RenderMan::render($terms);
  783. ?>
  784. </div>
  785. <p style="text-align: center;">
  786. <label>
  787. <input tabindex="7" type="checkbox" name="tou_agreed" />
  788. <b><?php echo $lang->get('user_reg_lbl_field_tou'); ?></b>
  789. </label>
  790. </p>
  791. </td>
  792. </tr>
  793. <?php
  794. endif; // !empty($terms)
  795. endif; // $session->user_logged_in
  796. ?>
  797. <!-- FIELD: submit button -->
  798. <tr>
  799. <th class="subhead" colspan="3" style="text-align: center;">
  800. <input tabindex="8" type="submit" name="submit" value="<?php echo $lang->get('user_reg_btn_create_account'); ?>" />
  801. </td>
  802. </tr>
  803. </table>
  804. </div>
  805. <?php
  806. $val = ( $coppa ) ? 'yes' : 'no';
  807. echo '<input type="hidden" name="coppa" value="' . $val . '" />';
  808. ?>
  809. <input type="hidden" name="challenge_data" value="<?php echo $challenge; ?>" />
  810. <input type="hidden" name="use_crypt" value="no" />
  811. <input type="hidden" name="crypt_key" value="<?php echo $pubkey; ?>" />
  812. <input type="hidden" name="crypt_data" value="" />
  813. <script type="text/javascript">
  814. // ENCRYPTION CODE
  815. function runEncryption()
  816. {
  817. var frm = document.forms.regform;
  818. if ( frm.password.value.length < 1 )
  819. return true;
  820. pass1 = frm.password.value;
  821. pass2 = frm.password_confirm.value;
  822. if ( pass1 != pass2 )
  823. {
  824. alert($lang.get('user_reg_err_alert_password_nomatch'));
  825. return false;
  826. }
  827. if ( pass1.length < 6 && pass1.length > 0 )
  828. {
  829. alert($lang.get('user_reg_err_alert_password_tooshort'));
  830. return false;
  831. }
  832. if(aes_self_test())
  833. {
  834. frm.use_crypt.value = 'yes';
  835. var cryptkey = frm.crypt_key.value;
  836. frm.crypt_key.value = hex_md5(cryptkey);
  837. cryptkey = hexToByteArray(cryptkey);
  838. if(!cryptkey || ( ( typeof cryptkey == 'string' || typeof cryptkey == 'object' ) ) && cryptkey.length != keySizeInBits / 8 )
  839. {
  840. frm.submit.disabled = true;
  841. len = ( typeof cryptkey == 'string' || typeof cryptkey == 'object' ) ? '\nLen: '+cryptkey.length : '';
  842. alert('The key is messed up\nType: '+typeof(cryptkey)+len);
  843. }
  844. pass = frm.password.value;
  845. pass = stringToByteArray(pass);
  846. cryptstring = rijndaelEncrypt(pass, cryptkey, 'ECB');
  847. if(!cryptstring)
  848. {
  849. return false;
  850. }
  851. cryptstring = byteArrayToHex(cryptstring);
  852. frm.crypt_data.value = cryptstring;
  853. frm.password.value = "";
  854. frm.password_confirm.value = "";
  855. }
  856. return true;
  857. }
  858. </script>
  859. </form>
  860. <!-- Don't optimize this script, it fails when compressed -->
  861. <enano:no-opt>
  862. <script type="text/javascript">
  863. // <![CDATA[
  864. var namegood = false;
  865. function validateForm(field)
  866. {
  867. if ( typeof(field) != 'object' )
  868. {
  869. field = {
  870. name: '_nil',
  871. value: '_nil'
  872. }
  873. }
  874. // wait until $lang is initted
  875. if ( typeof($lang) != 'object' )
  876. {
  877. setTimeout('validateForm();', 200);
  878. return false;
  879. }
  880. var frm = document.forms.regform;
  881. failed = false;
  882. // Username
  883. if(!namegood && ( field.name == 'username' || field.name == '_nil' ) )
  884. {
  885. //if(frm.username.value.match(/^([A-z0-9 \!@\-\(\)]+){2,}$/ig))
  886. var regex = new RegExp('^([^<>&\?]+){2,}$', 'ig');
  887. if ( frm.username.value.match(regex) )
  888. {
  889. document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/checkunk.png';
  890. document.getElementById('e_username').innerHTML = '&nbsp;';
  891. } else {
  892. failed = true;
  893. document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/checkbad.png';
  894. document.getElementById('e_username').innerHTML = '<br /><small>' + $lang.get('user_reg_err_username_invalid') + '</small>';
  895. }
  896. }
  897. if ( document.getElementById('b_username') )
  898. {
  899. document.getElementById('b_username').innerHTML = '';
  900. if(hex_md5(frm.real_name.value) == '5a397df72678128cf0e8147a2befd5f1')
  901. {
  902. document.getElementById('b_username').innerHTML = '<br /><br />Hey...I know you!<br /><img alt="" src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Bill_Gates_2004_cr.jpg/220px-Bill_Gates_2004_cr.jpg" />';
  903. }
  904. }
  905. // Password
  906. if ( field.name == 'password' || field.name == 'password_confirm' || field.name == '_nil' )
  907. {
  908. if(frm.password.value.match(/^(.+){6,}$/ig) && frm.password_confirm.value.match(/^(.+){6,}$/ig) && frm.password.value == frm.password_confirm.value )
  909. {
  910. document.getElementById('s_password').src='<?php echo scriptPath; ?>/images/check.png';
  911. document.getElementById('e_password').innerHTML = '<br /><small>' + $lang.get('user_reg_err_password_good') + '</small>';
  912. } else {
  913. failed = true;
  914. if(frm.password.value.length < 6)
  915. {
  916. document.getElementById('e_password').innerHTML = '<br /><small>' + $lang.get('user_reg_msg_password_length') + '</small>';
  917. }
  918. else if(frm.password.value != frm.password_confirm.value)
  919. {
  920. document.getElementById('e_password').innerHTML = '<br /><small>' + $lang.get('user_reg_msg_password_needmatch') + '</small>';
  921. }
  922. else
  923. {
  924. document.getElementById('e_password').innerHTML = '';
  925. }
  926. document.getElementById('s_password').src='<?php echo scriptPath; ?>/images/checkbad.png';
  927. }
  928. }
  929. // E-mail address
  930. // workaround for idiot jEdit bug
  931. if ( validateEmail(frm.email.value) && ( field.name == 'email' || field.name == '_nil' ) )
  932. {
  933. document.getElementById('s_email').src='<?php echo scriptPath; ?>/images/check.png';
  934. } else {
  935. failed = true;
  936. document.getElementById('s_email').src='<?php echo scriptPath; ?>/images/checkbad.png';
  937. }
  938. if(failed)
  939. {
  940. frm.submit.disabled = 'disabled';
  941. } else {
  942. frm.submit.disabled = false;
  943. }
  944. }
  945. function checkUsername()
  946. {
  947. var frm = document.forms.regform;
  948. if(!namegood)
  949. {
  950. var regex = new RegExp('^([^<>&\?]+){2,}$', 'ig');
  951. if ( frm.username.value.match(regex) )
  952. {
  953. document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/checkunk.png';
  954. document.getElementById('e_username').innerHTML = '&nbsp;';
  955. } else {
  956. document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/checkbad.png';
  957. document.getElementById('e_username').innerHTML = '<br /><small>' + $lang.get('user_reg_err_username_invalid') + '</small>';
  958. return false;
  959. }
  960. }
  961. document.getElementById('e_username').innerHTML = '<br /><small><b>' + $lang.get('user_reg_msg_username_checking') + '</b></small>';
  962. ajaxGet('<?php echo scriptPath; ?>/ajax.php?title=null&_mode=checkusername&name='+escape(frm.username.value), function() {
  963. if ( ajax.readyState == 4 && ajax.status == 200 )
  964. if(ajax.responseText == 'good')
  965. {
  966. document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/check.png';
  967. document.getElementById('e_username').innerHTML = '<br /><small><b>' + $lang.get('user_reg_msg_username_available') + '</b></small>';
  968. namegood = true;
  969. } else if(ajax.responseText == 'bad') {
  970. document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/checkbad.png';
  971. document.getElementById('e_username').innerHTML = '<br /><small><b>' + $lang.get('user_reg_msg_username_unavailable') + '</b></small>';
  972. namegood = false;
  973. } else {
  974. document.getElementById('e_username').innerHTML = ajax.responseText;
  975. }
  976. });
  977. }
  978. function regenCaptcha()
  979. {
  980. var frm = document.forms.regform;
  981. document.getElementById('captchaimg').src = '<?php echo makeUrlNS("Special", "Captcha/$captchacode"); ?>/'+Math.floor(Math.random() * 100000);
  982. frm.captchacode.value = '';
  983. return false;
  984. }
  985. function validateCaptcha(input)
  986. {
  987. var frm = document.forms.regform;
  988. if ( input.value.length < 7 )
  989. {
  990. return false;
  991. }
  992. var valid_field = document.getElementById('s_captcha');
  993. var loader_img = document.getElementById('captchaajax');
  994. loader_img.src = cdnPath + '/images/loading.gif';
  995. ajaxGet(makeUrlNS('Special', 'Captcha/' + frm.captchahash.value + '/validate=' + input.value), function(ajax)
  996. {
  997. if ( ajax.readyState == 4 && ajax.status == 200 )
  998. {
  999. var response = String(ajax.responseText + '');
  1000. if ( !check_json_response(response) )
  1001. {
  1002. handle_invalid_json(response);
  1003. return false;
  1004. }
  1005. response = parseJSON(response);
  1006. if ( response.valid )
  1007. {
  1008. loader_img.src = cdnPath + '/images/spacer.gif';
  1009. valid_field.src = cdnPath + '/images/check.png';
  1010. }
  1011. else
  1012. {
  1013. valid_field.src = cdnPath + '/images/checkbad.png';
  1014. regenCaptcha();
  1015. document.getElementById('captchaimg').onload = function()
  1016. {
  1017. document.getElementById('captchaajax').src = cdnPath + '/images/spacer.gif';
  1018. input.focus();
  1019. };
  1020. input.value = '';
  1021. }
  1022. }
  1023. });
  1024. }
  1025. addOnloadHook(function()
  1026. {
  1027. <?php if ( getConfig('pw_strength_enable') == '1' ): ?>
  1028. var frm = document.forms.regform;
  1029. load_component('pwstrength');
  1030. password_score_field(frm.password);
  1031. <?php endif; ?>
  1032. load_component('crypto');
  1033. validateForm();
  1034. setTimeout('checkUsername();', 1000);
  1035. });
  1036. // ]]>
  1037. </script>
  1038. </enano:no-opt>
  1039. <?php
  1040. }
  1041. else
  1042. {
  1043. $year = intval( enano_date('Y') );
  1044. $year = $year - 13;
  1045. $month = enano_date('F');
  1046. $day = enano_date('d');
  1047. $yo13_date = "$month $day, $year";
  1048. $link_coppa_yes = makeUrlNS('Special', 'Register', 'coppa=yes', true);
  1049. $link_coppa_no = makeUrlNS('Special', 'Register', 'coppa=no', true);
  1050. // COPPA enabled, ask age
  1051. echo '<div class="tblholder">';
  1052. echo '<table border="0" cellspacing="1" cellpadding="4">';
  1053. echo '<tr>
  1054. <td class="row1">
  1055. ' . $lang->get('user_reg_coppa_title') . '
  1056. </td>
  1057. </tr>
  1058. <tr>
  1059. <td class="row3">
  1060. <a href="' . $link_coppa_no . '">' . $lang->get('user_reg_coppa_link_atleast13', array( 'yo13_date' => $yo13_date )) . '</a><br />
  1061. <a href="' . $link_coppa_yes . '">' . $lang->get('user_reg_coppa_link_not13', array( 'yo13_date' => $yo13_date )) . '</a>
  1062. </td>
  1063. </tr>';
  1064. echo '</table>';
  1065. echo '</div>';
  1066. }
  1067. $template->footer();
  1068. }
  1069. function page_Special_Contributions()
  1070. {
  1071. global $db, $session, $paths, $template, $plugins; // Common objects
  1072. global $lang;
  1073. // This is a vast improvement over the old Special:Contributions in 1.0.x.
  1074. $template->header();
  1075. $user = $paths->getParam();
  1076. if ( !$user && isset($_GET['user']) )
  1077. {
  1078. $user = $_GET['user'];
  1079. }
  1080. else if ( !$user && !isset($_GET['user']) )
  1081. {
  1082. echo '<p>' . $lang->get('userfuncs_contribs_err_no_user') . '</p>';
  1083. $template->footer();
  1084. return;
  1085. }
  1086. $url = makeUrlNS("Special", "Log/user={$user}");
  1087. redirect($url, '', '', 0);
  1088. }
  1089. function page_Special_ChangeStyle()
  1090. {
  1091. global $db, $session, $paths, $template, $plugins; // Common objects
  1092. global $lang;
  1093. if ( !$session->user_logged_in )
  1094. {
  1095. die_friendly('Access denied', '<p>You must be logged in to change your style. Spoofer.</p>');
  1096. }
  1097. if(isset($_POST['theme']) && isset($_POST['style']) && isset($_POST['return_to']))
  1098. {
  1099. if ( !preg_match('/^([a-z0-9_-]+)$/i', $_POST['theme']) )
  1100. die('Hacking attempt');
  1101. if ( !preg_match('/^([a-z0-9_-]+)$/i', $_POST['style']) )
  1102. die('Hacking attempt');
  1103. $d = ENANO_ROOT . '/themes/' . $_POST['theme'];
  1104. $f = ENANO_ROOT . '/themes/' . $_POST['theme'] . '/css/' . $_POST['style'] . '.css';
  1105. if ( !file_exists($d) || !is_dir($d) )
  1106. {
  1107. die('The directory "'.$d.'" does not exist.');
  1108. }
  1109. if ( !file_exists($f) )
  1110. {
  1111. die('The file "'.$f.'" does not exist.');
  1112. }
  1113. $d = $db->escape($_POST['theme']);
  1114. $f = $db->escape($_POST['style']);
  1115. $q = 'UPDATE '.table_prefix.'users SET theme=\''.$d.'\',style=\''.$f.'\' WHERE username=\''.$session->username.'\'';
  1116. if ( !$db->sql_query($q) )
  1117. {
  1118. $db->_die('Your theme/style preferences were not updated.');
  1119. }
  1120. else
  1121. {
  1122. redirect(makeUrl($_POST['return_to']), $lang->get('userfuncs_changetheme_success_title'), $lang->get('userfuncs_changetheme_success_body'), 3);
  1123. }
  1124. }
  1125. else
  1126. {
  1127. $template->header();
  1128. $ret = ( isset($_POST['return_to']) ) ? $_POST['return_to'] : $paths->getParam(0);
  1129. if ( !$ret )
  1130. {
  1131. $ret = get_main_page();
  1132. }
  1133. ?>
  1134. <form action="<?php echo makeUrl($paths->page); ?>" method="post">
  1135. <?php if ( !isset($_POST['themeselected']) ) { ?>
  1136. <h3><?php echo $lang->get('userfuncs_changetheme_heading_theme'); ?></h3>
  1137. <p>
  1138. <select name="theme">
  1139. <?php
  1140. foreach ( $template->theme_list as $t )
  1141. {
  1142. if ( $t['enabled'] )
  1143. {
  1144. echo '<option value="'.$t['theme_id'].'"';
  1145. if ( $t['theme_id'] == $session->theme )
  1146. {
  1147. echo ' selected="selected"';
  1148. }
  1149. echo '>' . htmlspecialchars($t['theme_name']) . '</option>';
  1150. }
  1151. }
  1152. ?>
  1153. </select>
  1154. </p>
  1155. <p><input type="hidden" name="return_to" value="<?php echo htmlspecialchars($ret); ?>" />
  1156. <input type="submit" name="themeselected" value="<?php echo $lang->get('userfuncs_changetheme_btn_continue'); ?>" /></p>
  1157. <?php } else {
  1158. $theme = $_POST['theme'];
  1159. if ( !preg_match('/^([0-9A-z_-]+)$/i', $theme ) )
  1160. die('Hacking attempt');
  1161. ?>
  1162. <h3><?php echo $lang->get('userfuncs_changetheme_heading_style'); ?></h3>
  1163. <p>
  1164. <select name="style">
  1165. <?php
  1166. $dir = './themes/'.$theme.'/css/';
  1167. $list = Array();
  1168. // Open a known directory, and proceed to read its contents
  1169. if (is_dir($dir)) {
  1170. if ($dh = opendir($dir)) {
  1171. while (($file = readdir($dh)) !== false) {
  1172. if(preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css') {
  1173. $list[] = substr($file, 0, strlen($file)-4);
  1174. }
  1175. }
  1176. closedir($dh);
  1177. }
  1178. } else die($dir.' is not a dir');
  1179. foreach ( $list as $l )
  1180. {
  1181. echo '<option value="'.$l.'">'.ucfirst($l).'</option>';
  1182. }
  1183. ?>
  1184. </select>
  1185. </p>
  1186. <p><input type="hidden" name="return_to" value="<?php echo htmlspecialchars($ret); ?>" />
  1187. <input type="hidden" name="theme" value="<?php echo htmlspecialchars($theme); ?>" />
  1188. <input type="submit" name="allclear" value="<?php echo $lang->get('userfuncs_changetheme_btn_allclear'); ?>" /></p>
  1189. <?php } ?>
  1190. </form>
  1191. <?php
  1192. $template->footer();
  1193. }
  1194. }
  1195. function page_Special_ActivateAccount()
  1196. {
  1197. global $db, $session, $paths, $template, $plugins; // Common objects
  1198. global $lang;
  1199. $user = $paths->getParam(0);
  1200. if ( !$user )
  1201. {
  1202. die_friendly($lang->get('userfuncs_activate_err_badlink_title'), '<p>' . $lang->get('userfuncs_activate_err_badlink_body') . '</p>');
  1203. }
  1204. $user = str_replace('_', ' ', dirtify_page_id($user));
  1205. $key = $paths->getParam(1);
  1206. if ( !$key )
  1207. {
  1208. die_friendly($lang->get('userfuncs_activate_err_badlink_title'), '<p>' . $lang->get('userfuncs_activate_err_badlink_body') . '</p>');
  1209. }
  1210. $s = $session->activate_account(str_replace('_', ' ', $user), $key);
  1211. if ( $s )
  1212. {
  1213. die_friendly($lang->get('userfuncs_activate_success_title'), '<p>' . $lang->get('userfuncs_activate_success_body') . '</p>');
  1214. }
  1215. else
  1216. {
  1217. die_friendly($lang->get('userfuncs_activate_err_badlink_title'), '<p>' . $lang->get('userfuncs_activate_err_bad_key') . '</p>');
  1218. }
  1219. }
  1220. function page_Special_Captcha()
  1221. {
  1222. global $db, $session, $paths, $template, $plugins; // Common objects
  1223. if ( $paths->getParam(0) == 'make' )
  1224. {
  1225. $session->kill_captcha();
  1226. echo $session->make_captcha();
  1227. return;
  1228. }
  1229. $hash = $paths->getParam(0);
  1230. if ( !$hash || !preg_match('#^([0-9a-f]*){32,40}$#i', $hash) )
  1231. {
  1232. $paths->main_page();
  1233. }
  1234. if ( $validate_code = $paths->getParam(1) )
  1235. {
  1236. if ( preg_match('/^validate=(.+)$/', $validate_code, $match) )
  1237. {
  1238. header('Content-type: text/javascript');
  1239. $code = $session->get_captcha($hash, true);
  1240. $valid = strtolower($code) === strtolower($match[1]);
  1241. if ( !$valid )
  1242. {
  1243. $session->make_captcha(7, $hash);
  1244. }
  1245. echo enano_json_encode(array(
  1246. 'valid' => $valid
  1247. ));
  1248. exit;
  1249. }
  1250. }
  1251. $session->make_captcha(7, $hash);
  1252. $code = $session->generate_captcha_code();
  1253. // Avoid letting our captchas end up on failblog.org
  1254. // BTW, the last one was a real-life encounter: http://img822.imageshack.us/img822/3851/murderg.png
  1255. foreach ( array('shit', 'cock', 'fuck', 'nazi', 'cunt', 'clit', 'pussy', 'penis', 'piss', 'tits', 'murder') as $word )
  1256. {
  1257. if ( stristr($code, $word) )
  1258. {
  1259. // but don't put too much effort into this (will only correct this once)
  1260. // I mean, face it. If it generates one of those words twice in a row, either the local root has had
  1261. // way too much fun with his /dev/random, or this server is just plain gutter-minded.
  1262. $code = $session->generate_captcha_code();
  1263. break;
  1264. }
  1265. }
  1266. $q = $db->sql_query('UPDATE ' . table_prefix . "captcha SET code = '$code' WHERE session_id = '$hash';");
  1267. if ( !$q )
  1268. $db->_die();
  1269. require ( ENANO_ROOT.'/includes/captcha.php' );
  1270. try
  1271. {
  1272. $captcha = captcha_object($hash, 'freecap');
  1273. }
  1274. catch ( Exception $e )
  1275. {
  1276. die("CAPTCHA engine returned a hard exception");
  1277. }
  1278. // $captcha->debug = true;
  1279. $captcha->make_image();
  1280. exit;
  1281. }
  1282. function page_Special_PasswordReset()
  1283. {
  1284. global $db, $session, $paths, $template, $plugins; // Common objects
  1285. global $lang;
  1286. $template->header();
  1287. if($paths->getParam(0) == 'stage2')
  1288. {
  1289. require_once(ENANO_ROOT . '/includes/math.php');
  1290. require_once(ENANO_ROOT . '/includes/diffiehellman.php');
  1291. $user_id = intval($paths->getParam(1));
  1292. $encpass = $paths->getParam(2);
  1293. if ( $user_id < 2 )
  1294. {
  1295. echo '<p>Hacking attempt</p>';
  1296. $template->footer();
  1297. return false;
  1298. }
  1299. if(!preg_match('#^([a-f0-9]+)$#i', $encpass))
  1300. {
  1301. echo '<p>Hacking attempt</p>';
  1302. $template->footer();
  1303. return false;
  1304. }
  1305. $q = $db->sql_query('SELECT username,temp_password_time,temp_password,password_salt FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
  1306. if($db->numrows() < 1)
  1307. {
  1308. echo '<p>Invalid credentials</p>';
  1309. $template->footer();
  1310. return false;
  1311. }
  1312. $row = $db->fetchrow();
  1313. $db->free_result();
  1314. $temp_pass = $session->pk_decrypt($encpass);
  1315. $temp_hmac = hmac_sha1($temp_pass, $row['password_salt']);
  1316. if ( $temp_hmac !== $row['temp_password'] )
  1317. {
  1318. echo '<p>Invalid credentials</p>';
  1319. $template->footer();
  1320. return false;
  1321. }
  1322. if ( ( intval($row['temp_password_time']) + ( 3600 * 24 ) ) < time() )
  1323. {
  1324. echo '<p>' . $lang->get('userfuncs_passreset_err_pass_expired', array('reset_url' => makeUrlNS('Special', 'PasswordReset'))) . '</p>';
  1325. $template->footer();
  1326. return false;
  1327. }
  1328. if ( isset($_POST['do_stage2']) )
  1329. {
  1330. $data = $session->get_aes_post('pass');
  1331. if(empty($data))
  1332. {
  1333. echo 'ERROR: Sanity check failed!';
  1334. $template->footer();
  1335. return false;
  1336. }
  1337. if ( strlen($data) < 6 )
  1338. {
  1339. echo '<p>' . $lang->get('userfuncs_passreset_err_too_short') . '</p>';
  1340. $template->footer();
  1341. return false;
  1342. }
  1343. if ( $_POST['use_crypt'] == 'no' )
  1344. {
  1345. if ( $_POST['pass'] !== $_POST['pass_confirm'] )
  1346. {
  1347. echo '<p>' . $lang->get('userfuncs_passreset_err_no_match') . '</p>';
  1348. $template->footer();
  1349. return false;
  1350. }
  1351. }
  1352. if ( getConfig('pw_strength_enable') == 1 )
  1353. {
  1354. $min_score = intval(getConfig('pw_strength_minimum'));
  1355. $inp_score = password_score($data);
  1356. if ( $inp_score < $min_score )
  1357. {
  1358. $url = makeUrl($paths->fullpage);
  1359. echo "<p>" . $lang->get('userfuncs_passreset_err_failed_score', array('inp_score' => $inp_score, 'url' => $url)) . "</p>";
  1360. $template->footer();
  1361. return false;
  1362. }
  1363. }
  1364. $session->set_password($user_id, $data);
  1365. $q = $db->sql_query('UPDATE '.table_prefix.'users SET temp_password=\'\',temp_password_time=0 WHERE user_id = '.$user_id.';');
  1366. if($q)
  1367. {
  1368. $session->login_without_crypto($row['username'], $data);
  1369. echo '<p>' . $lang->get('userfuncs_passreset_stage2_success', array('url_mainpage' => makeUrl(get_main_page()))) . '</p>';
  1370. }
  1371. else
  1372. {
  1373. echo $db->get_error();
  1374. }
  1375. $template->footer();
  1376. return false;
  1377. }
  1378. // Password reset form
  1379. $evt_get_score = ( getConfig('pw_strength_enable') == '1' ) ? 'onkeyup="password_score_field(this);" ' : '';
  1380. $pw_meter = ( getConfig('pw_strength_enable') == '1' ) ? '<tr><td class="row1">' . $lang->get('userfuncs_passreset_stage2_lbl_strength') . '</td><td class="row1"><div id="pwmeter"></div></td></tr>' : '';
  1381. $pw_blurb = ( getConfig('pw_strength_enable') == '1' && intval(getConfig('pw_strength_minimum')) > -10 ) ? '<br /><small>' . $lang->get('userfuncs_passreset_stage2_blurb_strength') . '</small>' : '';
  1382. ?>
  1383. <form action="<?php echo makeUrl($paths->fullpage); ?>" method="post" name="resetform" onsubmit="return runEncryption();">
  1384. <br />
  1385. <div class="tblholder">
  1386. <table border="0" style="width: 100%;" cellspacing="1" cellpadding="4">
  1387. <tr><th colspan="2"><?php echo $lang->get('userfuncs_passreset_stage2_th'); ?></th></tr>
  1388. <tr><td class="row1"><?php echo $lang->get('userfuncs_passreset_stage2_lbl_password'); ?> <?php echo $pw_blurb; ?></td><td class="row1"><input name="pass" type="password" <?php echo $evt_get_score; ?>/></td></tr>
  1389. <tr><td class="row2"><?php echo $lang->get('userfuncs_passreset_stage2_lbl_confirm'); ?> </td><td class="row2"><input name="pass_confirm" type="password" /></td></tr>
  1390. <?php echo $pw_meter; ?>
  1391. <tr>
  1392. <td colspan="2" class="row3" style="text-align: center;">
  1393. <input type="submit" name="do_stage2" value="<?php echo $lang->get('userfuncs_passreset_stage2_btn_submit'); ?>" />
  1394. </td>
  1395. </tr>
  1396. </table>
  1397. </div>
  1398. <?php echo $session->generate_aes_form(); ?>
  1399. </form>
  1400. <?php if ( getConfig('pw_strength_enable') == 1 ): ?>
  1401. <script type="text/javascript">
  1402. addOnloadHook(function()
  1403. {
  1404. load_component('pwstrength');
  1405. password_score_field(document.forms.resetform.pass);
  1406. });
  1407. </script>
  1408. <?php
  1409. endif;
  1410. echo $session->aes_javascript('resetform', 'pass', 'use_crypt', 'crypt_key', 'crypt_data', 'challenge_data', 'dh_supported', 'dh_public_key', 'dh_client_public_key');
  1411. $template->footer();
  1412. return true;
  1413. }
  1414. if ( $session->user_logged_in )
  1415. {
  1416. $paths->main_page();
  1417. }
  1418. if(isset($_POST['do_reset']))
  1419. {
  1420. if($session->mail_password_reset($_POST['username']))
  1421. {
  1422. echo '<p>' . $lang->get('userfuncs_passreset_stage1_success') . '</p>';
  1423. }
  1424. else
  1425. {
  1426. echo '<p>' . $lang->get('userfuncs_passreset_stage1_error') . '</p>';
  1427. }
  1428. $template->footer();
  1429. return true;
  1430. }
  1431. echo '<p>' . $lang->get('userfuncs_passreset_blurb_line1') . '</p>
  1432. <p>' . $lang->get('userfuncs_passreset_blurb_line2') . '</p>
  1433. <form action="'.makeUrl($paths->page).'" method="post" onsubmit="if(!submitAuthorized) return false;">
  1434. <p>' . $lang->get('userfuncs_passreset_lbl_username') . ' '.$template->username_field('username').'</p>
  1435. <p><input type="submit" name="do_reset" value="' . $lang->get('userfuncs_passreset_btn_mailpasswd') . '" /></p>
  1436. </form>';
  1437. $template->footer();
  1438. }
  1439. function page_Special_Memberlist()
  1440. {
  1441. global $db, $session, $paths, $template, $plugins; // Common objects
  1442. global $lang;
  1443. $template->header();
  1444. $startletters = 'abcdefghijklmnopqrstuvwxyz';
  1445. $startletters = enano_str_split($startletters);
  1446. $startletter = ( isset($_GET['letter']) ) ? strtolower($_GET['letter']) : '';
  1447. if ( !in_array($startletter, $startletters) && $startletter != 'chr' )
  1448. {
  1449. $startletter = '';
  1450. }
  1451. $startletter_sql = $startletter;
  1452. if ( $startletter == 'chr' )
  1453. {
  1454. $startletter_sql = '([^a-z])';
  1455. }
  1456. // offset
  1457. $perpage = 25;
  1458. $page = (( isset($_GET['offset']) && strval(intval($_GET['offset'])) === $_GET['offset']) ? intval($_GET['offset']) : 1) - 1;
  1459. $offset = $page * $perpage;
  1460. // sort order
  1461. $sortkeys = array(
  1462. 'uid' => 'u.user_id',
  1463. 'username' => 'u.username',
  1464. 'email' => 'u.email',
  1465. 'regist' => 'u.reg_time'
  1466. );
  1467. $sortby = ( isset($_GET['sort']) && isset($sortkeys[$_GET['sort']]) ) ? $_GET['sort'] : 'username';
  1468. $sort_sqllet = $sortkeys[$sortby];
  1469. $target_order = ( isset($_GET['orderby']) && in_array($_GET['orderby'], array('ASC', 'DESC')) )? $_GET['orderby'] : 'ASC';
  1470. $sortorders = array();
  1471. foreach ( $sortkeys as $k => $_unused )
  1472. {
  1473. $sortorders[$k] = ( $sortby == $k ) ? ( $target_order == 'ASC' ? 'DESC' : 'ASC' ) : 'ASC';
  1474. }
  1475. // Why 3.3714%? 100 percent / 28 cells, minus a little (0.2% / cell) to account for cell spacing
  1476. echo '<div class="tblholder">
  1477. <table border="0" cellspacing="1" cellpadding="4" style="text-align: center;">
  1478. <tr>';
  1479. echo '<td class="row1" style="width: 3.3714%;"><a href="' . makeUrlNS('Special', 'Memberlist', 'letter=&sort=' . $sortby . '&orderby=' . $target_order, true) . '">All</a></td>';
  1480. echo '<td class="row1" style="width: 3.3714%;"><a href="' . makeUrlNS('Special', 'Memberlist', 'letter=chr&sort=' . $sortby . '&orderby=' . $target_order, true) . '">#</a></td>';
  1481. foreach ( $startletters as $letter )
  1482. {
  1483. echo '<td class="row1" style="width: 3.3714%;"><a href="' . makeUrlNS('Special', 'Memberlist', 'letter=' . $letter . '&sort=' . $sortby . '&orderby=' . $target_order, true) . '">' . strtoupper($letter) . '</a></td>';
  1484. }
  1485. echo ' </tr>
  1486. </table>
  1487. </div>';
  1488. // User search
  1489. if ( isset($_GET['finduser']) )
  1490. {
  1491. $finduser = str_replace(array( '%', '_'),
  1492. array('\\%', '\\_'),
  1493. $_GET['finduser']);
  1494. $finduser = str_replace(array('*', '?'),
  1495. array('%', '_'),
  1496. $finduser);
  1497. $finduser = $db->escape($finduser);
  1498. $username_where = ENANO_SQLFUNC_LOWERCASE . '(u.username) LIKE \'%' . strtolower($finduser) . '%\' OR u.username LIKE \'' . $finduser . '\'';
  1499. $finduser_url = 'finduser=' . rawurlencode($_GET['finduser']) . '&';
  1500. }
  1501. else
  1502. {
  1503. if ( ENANO_DBLAYER == 'MYSQL' )
  1504. $username_where = 'lcase(u.username) REGEXP lcase("^' . $startletter_sql . '")';
  1505. else if ( ENANO_DBLAYER == 'PGSQL' )
  1506. $username_where = 'lower(u.username) ~ lower(\'^' . $startletter_sql . '\')';
  1507. $finduser_url = '';
  1508. }
  1509. // Column markers
  1510. $headings = '<tr>
  1511. <th style="max-width: 50px;">
  1512. <a href="' . makeUrlNS('Special', 'Memberlist', $finduser_url . 'letter=' . $startletter . '&sort=uid&orderby=' . $sortorders['uid'], true) . '">#</a>
  1513. </th>
  1514. <th>
  1515. <a href="' . makeUrlNS('Special', 'Memberlist', $finduser_url . 'letter=' . $startletter . '&sort=username&orderby=' . $sortorders['username'], true) . '">' . $lang->get('userfuncs_ml_column_username') . '</a>
  1516. </th>
  1517. <th>
  1518. ' . $lang->get('userfuncs_ml_column_userlevel') . '
  1519. </th>
  1520. <th>
  1521. <a href="' . makeUrlNS('Special', 'Memberlist', $finduser_url . 'letter=' . $startletter . '&sort=email&orderby=' . $sortorders['email'], true) . '">' . $lang->get('userfuncs_ml_column_email') . '</a>
  1522. </th>
  1523. <th>
  1524. <a href="' . makeUrlNS('Special', 'Memberlist', $finduser_url . 'letter=' . $startletter . '&sort=regist&orderby=' . $sortorders['regist'], true) . '">' . $lang->get('userfuncs_ml_column_regtime') . '</a>
  1525. </th>
  1526. </tr>';
  1527. // determine number of rows
  1528. $q = $db->sql_query('SELECT COUNT(u.user_id) FROM '.table_prefix.'users AS u WHERE ' . $username_where . ' AND u.username != \'Anonymous\';');
  1529. if ( !$q )
  1530. $db->_die();
  1531. list($num_rows) = $db->fetchrow_num();
  1532. $db->free_result();
  1533. if ( !empty($finduser_url) )
  1534. {
  1535. switch ( $num_rows )
  1536. {
  1537. case 0:
  1538. $str = ''; /* $lang->get('userfuncs_ml_msg_matches_zero'); */ break;
  1539. case 1:
  1540. $str = $lang->get('userfuncs_ml_msg_matches_one'); break;
  1541. default:
  1542. $str = $lang->get('userfuncs_ml_msg_matches', array('matches' => $num_rows)); break;
  1543. }
  1544. echo "<h3>$str</h3>";
  1545. }
  1546. // main selector
  1547. $pgsql_additional_group_by = ( ENANO_DBLAYER == 'PGSQL' ) ? ', u.username, u.reg_time, u.email, u.user_level, u.user_has_avatar, u.avatar_type, x.email_public' : '';
  1548. $q = $db->sql_query('SELECT \'\' AS infobit, u.user_id, u.username, u.reg_time, u.email, u.user_level, u.user_has_avatar, u.avatar_type, x.email_public, COUNT(c.comment_id) AS num_comments FROM '.table_prefix.'users AS u
  1549. LEFT JOIN '.table_prefix.'users_extra AS x
  1550. ON ( u.user_id = x.user_id )
  1551. LEFT JOIN ' . table_prefix . 'comments AS c
  1552. ON ( u.user_id = c.user_id )
  1553. WHERE ' . $username_where . ' AND u.username != \'Anonymous\'
  1554. GROUP BY u.user_id' . $pgsql_additional_group_by . '
  1555. ORDER BY ' . $sort_sqllet . ' ' . $target_order . '
  1556. LIMIT ' . $perpage . ' OFFSET ' . $offset . ';');
  1557. if ( !$q )
  1558. $db->_die();
  1559. // formatter parameters
  1560. $formatter = new MemberlistFormatter();
  1561. $formatters = array(
  1562. 'username' => array($formatter, 'username'),
  1563. 'user_level' => array($formatter, 'user_level'),
  1564. 'email' => array($formatter, 'email'),
  1565. 'reg_time' => array($formatter, 'reg_time'),
  1566. 'infobit' => array($formatter, 'infobit')
  1567. );
  1568. $result_url = makeUrlNS('Special', 'Memberlist', ( str_replace('%', '%%', $finduser_url) ) . 'letter=' . $startletter . '&offset=%s&sort=' . $sortby . '&orderby=' . $target_order );
  1569. $paginator = generate_paginator($page, ceil($num_rows / $perpage), $result_url);
  1570. if ( $num_rows > 0 )
  1571. {
  1572. if ( $num_rows > $perpage )
  1573. echo $paginator;
  1574. echo '<div class="tblholder">
  1575. <table border="0" cellspacing="1" cellpadding="4" style="text-align: center;">
  1576. ' . $headings;
  1577. $i = 0;
  1578. while ( $row = $db->fetchrow($q) )
  1579. {
  1580. $i++;
  1581. $cls = ( $i % 2 == 0 ) ? 'row2' : 'row1';
  1582. echo '<tr>';
  1583. echo '<td class="' . $cls . '">' . $row['user_id'] . '</td>';
  1584. echo '<td class="' . $cls . '" style="text-align: left;">' . $formatter->username($row['username'], $row) . '</td>';
  1585. echo '<td class="' . $cls . '">' . $formatter->user_level($row['user_level'], $row) . '</td>';
  1586. echo '<td class="' . $cls . '">' . $formatter->email($row['email'], $row) . '</td>';
  1587. echo '<td class="' . $cls . '">' . $formatter->reg_time($row['reg_time'], $row) . '</td>';
  1588. echo '</tr>';
  1589. echo '<tr>';
  1590. echo '<td colspan="5" class="row3" style="text-align: left;">
  1591. <div id="ml_moreinfo_' . $row['user_id'] . '" style="display: none;">
  1592. ' . $formatter->infobit(true, $row) . '
  1593. </div>
  1594. </td>';
  1595. echo '</tr>';
  1596. }
  1597. echo ' ' . $headings . '
  1598. </table>
  1599. </div>
  1600. ';
  1601. if ( $num_rows > $perpage )
  1602. echo $paginator;
  1603. }
  1604. else
  1605. {
  1606. echo '<h2 class="emptymessage">' . $lang->get('log_msg_no_results') . '</h2>';
  1607. }
  1608. echo '<div style="float: left;">
  1609. <form action="' . makeUrlNS('Special', 'Memberlist') . '" method="get" onsubmit="if ( !submitAuthorized ) return false;">'
  1610. . ( urlSeparator == '&' ? '<input type="hidden" name="title" value="' . htmlspecialchars( $paths->page ) . '" />' : '' )
  1611. . ( $session->sid_super ? '<input type="hidden" name="auth" value="' . $session->sid_super . '" />' : '')
  1612. . '<p>' . $lang->get('userfuncs_ml_lbl_finduser') . ' ' . $template->username_field('finduser') . ' <input type="submit" value="' . $lang->get('userfuncs_ml_btn_go') . '" /><br />
  1613. <small>' . $lang->get('userfuncs_ml_tip_wildcard') . '</small></p>'
  1614. . '</form>
  1615. </div>';
  1616. $template->footer();
  1617. }
  1618. /**
  1619. * Class for formatting results for the memberlist.
  1620. * @access private
  1621. */
  1622. class MemberlistFormatter
  1623. {
  1624. function username($username, $row)
  1625. {
  1626. global $db, $session, $paths, $template, $plugins; // Common objects
  1627. global $lang;
  1628. $userpage = $paths->nslist['User'] . sanitize_page_id($username);
  1629. $class = ( isPage($userpage) ) ? '' : ' class="wikilink-nonexistent"';
  1630. $anchor = '<a href="' . makeUrlNS('User', sanitize_page_id($username)) . '"' . $class . ' onclick="load_component(\'jquery\'); load_component(\'jquery-ui\'); var el = document.getElementById(\'ml_moreinfo_' . $row['user_id'] . '\'); $(el).toggle(\'blind\'); return false;">' . htmlspecialchars($username) . '</a>';
  1631. if ( $session->user_level >= USER_LEVEL_ADMIN )
  1632. {
  1633. $anchor .= ' <small>- <a href="' . makeUrlNS('Special', 'Administration', 'module=' . $paths->nslist['Admin'] . 'UserManager&src=get&username=' . urlencode($username), true) . '"
  1634. onclick="ajaxAdminUser(\'' . addslashes(htmlspecialchars($username)) . '\'); return false;">' . $lang->get('userfuncs_ml_btn_adminuser') . '</a></small>';
  1635. }
  1636. return $anchor;
  1637. }
  1638. function user_level($level, $row)
  1639. {
  1640. global $db, $session, $paths, $template, $plugins; // Common objects
  1641. global $lang;
  1642. /*
  1643. switch ( $level )
  1644. {
  1645. case USER_LEVEL_GUEST:
  1646. $s_level = $lang->get('userfuncs_ml_level_guest'); break;
  1647. case USER_LEVEL_MEMBER:
  1648. case USER_LEVEL_CHPREF:
  1649. $s_level = $lang->get('userfuncs_ml_level_member'); break;
  1650. case USER_LEVEL_MOD:
  1651. $s_level = $lang->get('userfuncs_ml_level_mod'); break;
  1652. case USER_LEVEL_ADMIN:
  1653. $s_level = $lang->get('userfuncs_ml_level_admin'); break;
  1654. default:
  1655. $s_level = $lang->get('userfuncs_ml_level_unknown', array( 'level' => $level ));
  1656. }
  1657. */
  1658. // TODO: Requested by mm3. Is this too CPU-intensive? Optimize?
  1659. // Performance yield =/= about the same (but only 4 users under testing conditions)
  1660. $rankdata = $session->get_user_rank($row['user_id']);
  1661. $s_level = '<span style="' . $rankdata['rank_style'] . '">' . $lang->get($rankdata['rank_title']) . '</span>';
  1662. return $s_level;
  1663. }
  1664. function email($addy, $row)
  1665. {
  1666. global $lang;
  1667. if ( $row['email_public'] == '1' )
  1668. {
  1669. global $email;
  1670. $addy = $email->encryptEmail($addy);
  1671. return $addy;
  1672. }
  1673. else
  1674. {
  1675. return '<small>&lt;' . $lang->get('userfuncs_ml_email_nonpublic') . '&gt;</small>';
  1676. }
  1677. }
  1678. /**
  1679. * Format a time as a reference to a day, with user-friendly "X days ago"/"Today"/"Yesterday" returned when relevant.
  1680. * @param int UNIX timestamp
  1681. * @return string
  1682. */
  1683. public static function format_date($time)
  1684. {
  1685. // merged into enano_date() :)
  1686. return enano_date(ED_DATE, $time);
  1687. }
  1688. function reg_time($time, $row)
  1689. {
  1690. return $this->format_date($time);
  1691. }
  1692. function infobit($_, $row)
  1693. {
  1694. global $db, $session, $paths, $template, $plugins; // Common objects
  1695. global $lang;
  1696. $bit = '';
  1697. if ( $row['user_has_avatar'] == 1 )
  1698. {
  1699. $bit .= '<div style="float: left; margin-right: 10px;">
  1700. <img alt=" " src="' . make_avatar_url(intval($row['user_id']), $row['avatar_type'], $row['email']) . '" />
  1701. </div>';
  1702. }
  1703. $rank_data = $session->get_user_rank(intval($row['user_id']));
  1704. $userpage = $paths->nslist['User'] . sanitize_page_id($row['username']);
  1705. $title = ( isPage($userpage) ) ? ' title="' . $lang->get('userfuncs_ml_tip_userpage') . '"' : ' title="' . $lang->get('userfuncs_ml_tip_nouserpage') . '"';
  1706. $bit .= '<a' . $title . ' href="' . makeUrlNS('User', $row['username'], false, true) . '" style="font-size: x-large; ' . $rank_data['rank_style'] . '">' . htmlspecialchars($row['username']) . '</a><br />';
  1707. if ( $rank_data['user_title'] )
  1708. $bit .= htmlspecialchars($rank_data['user_title']) . '<br />';
  1709. if ( $rank_data['rank_title'] )
  1710. $bit .= '<small>' . htmlspecialchars($lang->get($rank_data['rank_title'])) . '</small><br />';
  1711. $bit .= '<div style="text-align: right;">
  1712. <a href="' . makeUrlNS('Special', "PrivateMessages/Compose/To/{$row['username']}", false, true) . '" class="abutton icon abutton_blue" style="background-image: url(' . cdnPath . '/images/icons/send_pm.png);">' . $lang->get('comment_btn_send_privmsg') . '</a>
  1713. <a href="' . makeUrlNS('Special', "PrivateMessages/FriendList/Add/{$row['username']}", false, true) . '" class="abutton icon abutton_green" style="background-image: url(' . cdnPath . '/images/icons/add_buddy.png);">' . $lang->get('comment_btn_add_buddy') . '</a>
  1714. </div>';
  1715. return $bit;
  1716. }
  1717. }
  1718. function page_Special_LangExportJSON()
  1719. {
  1720. global $db, $session, $paths, $template, $plugins; // Common objects
  1721. global $lang;
  1722. $lang_id = ( $x = $paths->getParam(0) ) ? intval($x) : $lang->lang_id;
  1723. if ( $lang->lang_id == $lang_id )
  1724. $lang_local =& $lang;
  1725. else
  1726. $lang_local = new Language($lang_id);
  1727. $lang_local->get('meta_meta');
  1728. $lang_strings = enano_json_encode($lang_local->strings);
  1729. $etag = substr(sha1($lang_strings), 0, 20) . '-' . dechex($lang_local->lang_timestamp);
  1730. if ( isset($_SERVER['HTTP_IF_NONE_MATCH']) )
  1731. {
  1732. if ( "\"$etag\"" == $_SERVER['HTTP_IF_NONE_MATCH'] )
  1733. {
  1734. header('HTTP/1.1 304 Not Modified');
  1735. exit();
  1736. }
  1737. }
  1738. $timestamp = enano_date('D, j M Y H:i:s T', $lang_local->lang_timestamp);
  1739. // generate expires header
  1740. $expires = date('r', mktime(-1, -1, -1, -1, -1, intval(date('y'))+1));
  1741. header("Last-Modified: $timestamp");
  1742. header("Date: $timestamp");
  1743. header("ETag: \"$etag\"");
  1744. header('Content-type: text/javascript');
  1745. header("Expires: $expires");
  1746. $lang_local->fetch();
  1747. echo "if ( typeof(enano_lang) != 'object' )
  1748. var enano_lang = new Object();
  1749. enano_lang[{$lang_local->lang_id}] = " . $lang_strings . ";";
  1750. gzip_output();
  1751. exit(0);
  1752. }
  1753. /**
  1754. * Fetches and displays an avatar from the filesystem. Avatar fetching is abstracted as of 1.1.4.
  1755. */
  1756. function page_Special_Avatar()
  1757. {
  1758. global $db, $session, $paths, $template, $plugins; // Common objects
  1759. global $aggressive_optimize_html;
  1760. $aggressive_optimize_html = false;
  1761. $img_types = array(
  1762. IMAGE_TYPE_PNG => 'png',
  1763. IMAGE_TYPE_GIF => 'gif',
  1764. IMAGE_TYPE_JPG => 'jpg',
  1765. IMAGE_TYPE_GRV => 'grv'
  1766. );
  1767. $avi_id = $paths->getParam(0);
  1768. if ( !$avi_id || !@preg_match('/^[a-f0-9]+$/', $avi_id) )
  1769. {
  1770. echo 'Doesn\'t match the regexp';
  1771. return true;
  1772. }
  1773. $avi_id_dec = hexdecode($avi_id);
  1774. $avi_id_dec = @unpack('Vdate/Vuid/vimg_type', $avi_id_dec);
  1775. if ( !$avi_id_dec )
  1776. {
  1777. echo 'Bad unpack';
  1778. return true;
  1779. }
  1780. // check parameters
  1781. if ( !isset($img_types[$avi_id_dec['img_type']]) )
  1782. {
  1783. echo 'Invalid image type';
  1784. return true;
  1785. }
  1786. // build file path
  1787. $avi_type = $img_types[$avi_id_dec['img_type']];
  1788. // is this a gravatar?
  1789. if ( $avi_type == 'grv' )
  1790. {
  1791. // yes, we'll have to redirect
  1792. // sanitize UID
  1793. $uid = intval($avi_id_dec['uid']);
  1794. // fetch email
  1795. $q = $db->sql_query('SELECT email FROM ' . table_prefix . "users WHERE user_id = $uid;");
  1796. if ( !$q )
  1797. $db->_die();
  1798. if ( $db->numrows() < 1 )
  1799. return false;
  1800. list($email) = $db->fetchrow_num();
  1801. $db->free_result();
  1802. $url = make_gravatar_url($url);
  1803. // ship out the redirect
  1804. header('HTTP/1.1 302 Permanent Redirect');
  1805. header("Location: $url");
  1806. }
  1807. $avi_path = ENANO_ROOT . '/' . getConfig('avatar_directory') . '/' . $avi_id_dec['uid'] . '.' . $avi_type;
  1808. if ( file_exists($avi_path) )
  1809. {
  1810. $avi_mod_time = @filemtime($avi_path);
  1811. $avi_mod_time = date('r', $avi_mod_time);
  1812. $avi_size = @filesize($avi_path);
  1813. header("Last-Modified: $avi_mod_time");
  1814. header("Content-Length: $avi_size");
  1815. header("Content-Type: image/$avi_type");
  1816. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
  1817. header("Cache-Control: public");
  1818. // expire it 30 days from now
  1819. $expiry_time = time() + ( 86400 * 30 );
  1820. header("Expires: " . date('r', $expiry_time));
  1821. $fh = @fopen($avi_path, 'r');
  1822. if ( !$fh )
  1823. {
  1824. echo 'Could not open file';
  1825. return true;
  1826. }
  1827. while ( $fd = @fread($fh, 1024) )
  1828. {
  1829. echo $fd;
  1830. }
  1831. fclose($fh);
  1832. }
  1833. return true;
  1834. }
  1835. ?>