Advertisement
Guest User

Untitled

a guest
Jun 27th, 2017
225
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 83.01 KB | None | 0 0
  1. <?php
  2.  
  3. # Класс пользователей
  4.  
  5. class Users extends UsersBase
  6. {
  7.  
  8. public function authPage($sTemplate, $sTitle = '', array $aData = array())
  9. {
  10. tpl::includeJS('users.auth', false, 4);
  11. $aData['back'] = Request::referer(static::urlBase());
  12.  
  13. return $this->showShortPage($sTitle, $this->viewPHP($aData, $sTemplate));
  14. }
  15.  
  16. /**
  17. * Авторизация
  18. */
  19. public function login()
  20. {
  21. switch ($this->input->getpost('step', TYPE_STR))
  22. {
  23. case 'resend-activation': # Повторная отправка письма "активации"
  24. {
  25. $aResponse = array();
  26. do {
  27. $aData = $this->input->postgetm(array(
  28. 'email' => array(TYPE_NOTAGS, 'len' => 100), # E-mail
  29. 'pass' => TYPE_NOTRIM, # Пароль (в открытом виде)
  30. ));
  31. extract($aData);
  32.  
  33. if (!$this->security->validateReferer()) {
  34. $this->errors->reloadPage(); break;
  35. }
  36. # не чаще чем раз в {X} секунд с одного IP (для одного пользователя)
  37. if (Site::i()->preventSpam('users-login-resend-activation', 5, false)) {
  38. $this->errors->set(_t('', 'Повторите попытку через несколько секунд'));
  39. break;
  40. }
  41. # уже авторизован
  42. if (User::id()) {
  43. $this->errors->reloadPage();
  44. break;
  45. }
  46. # проверяем email
  47. if (!$this->input->isEmail($email)) {
  48. $this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
  49. break;
  50. }
  51. $userData = $this->model->userDataByFilter(array('email'=>$email),
  52. array('user_id', 'email', 'name', 'password', 'password_salt', 'activated', 'activate_key', 'phone_number'));
  53. if (empty($userData) || $userData['activated']) {
  54. $this->errors->reloadPage();
  55. break;
  56. }
  57. # телефон
  58. if (static::registerPhone() && !empty($userData['phone_number'])) {
  59. $this->errors->reloadPage();
  60. break;
  61. }
  62. # проверяем пароль
  63. if ($userData['password'] != $this->security->getUserPasswordMD5($pass, $userData['password_salt'])) {
  64. $this->errors->set(_t('users', 'E-mail или пароль указаны некорректно'), 'email');
  65. break;
  66. }
  67. # генерируем ссылку активации
  68. $activationData = $this->updateActivationKey($userData['user_id'], $userData['activate_key']);
  69. if ( ! $activationData) {
  70. $this->errors->reloadPage();
  71. break;
  72. }
  73.  
  74. # отправляем письмо для активации аккаунта
  75. $mailData = array(
  76. 'id' => $userData['user_id'],
  77. 'name' => $userData['name'],
  78. 'password' => $pass,
  79. 'email' => $email,
  80. 'activate_link' => $activationData['link']
  81. );
  82. bff::sendMailTemplate($mailData, 'users_register', $email);
  83.  
  84. # сохраняем данные для повторной отправки письма
  85. $this->security->sessionStart();
  86. $this->security->setSESSION('users-register-data', $mailData);
  87.  
  88. $aResponse['redirect'] = static::url('register', array('step'=>'emailed', 'resend'=>1));
  89. } while(false);
  90. $this->ajaxResponseForm($aResponse);
  91. }
  92. break;
  93. }
  94.  
  95. if (Request::isPOST())
  96. {
  97. $aData = $this->input->postm(array(
  98. 'email' => array(TYPE_NOTAGS, 'len' => 100), # E-mail
  99. 'pass' => TYPE_NOTRIM, # Пароль
  100. 'social' => TYPE_BOOL, # Авторизация через соц. сеть
  101. 'remember' => TYPE_BOOL, # Запомнить меня
  102. 'back' => TYPE_NOTAGS, # Ссылка возврата
  103. ));
  104. extract($aData);
  105.  
  106. $aResponse = array('success' => false, 'status' => 0);
  107. do {
  108. # уже авторизован
  109. if (User::id()) {
  110. $aResponse['success'] = true;
  111. break;
  112. }
  113.  
  114. # проверяем корректность email
  115. if (!$this->input->isEmail($email)) {
  116. $this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
  117. break;
  118. }
  119.  
  120. # при авторизации проверяем блокировку по IP
  121. if ($mBlocked = $this->checkBan(true)) {
  122. $this->errors->set(_t('users', 'Доступ заблокирован по причине: [reason]', array('reason' => $mBlocked)));
  123. break;
  124. }
  125.  
  126. # не чаще чем раз в {X} секунд с одного IP (для одного пользователя)
  127. if (Site::i()->preventSpam('users-login', rand(3,6), false)) {
  128. $this->errors->set(_t('', 'Повторите попытку через несколько секунд'));
  129. break;
  130. }
  131.  
  132. $mResult = $this->userAuth($email, 'email', $pass, false, true);
  133. if ($mResult === true) {
  134. $nUserID = User::id();
  135.  
  136. # привязываем соц. аккаунт
  137. if ($social) {
  138. $this->social()->authFinish($nUserID);
  139. }
  140.  
  141. # пересохраняем избранные ОБ из куков в базу
  142. BBS::i()->saveFavoritesToDB($nUserID);
  143.  
  144. $aResponse['status'] = 2; # успешная авторизация
  145. $aResponse['success'] = true;
  146. if ($remember) {
  147. $this->security->setRememberMe($this->security->getUserLogin(), $this->security->getUserPasswordMD5($pass));
  148. }
  149. } elseif ($mResult === 1) {
  150. $aResponse['status'] = 1; # необходимо активировать аккаунт
  151. $userData = config::get('__users_preactivate_data');
  152. $userData = $this->model->userData($userData['id'], array('user_id as id','email','name','activate_key','phone_number'));
  153. if (static::registerPhone() && !empty($userData['phone_number'])) {
  154. if (empty($userData['activate_key'])) {
  155. # Обновляем ключ активации
  156. $activationData = $this->updateActivationKey($userData['id']);
  157. if (!$activationData) {
  158. $this->errors->set(_t('users', 'Ошибка регистрации, обратитесь к администратору'));
  159. break;
  160. } else {
  161. $userData['activate_key'] = $activationData['key'];
  162. }
  163. }
  164.  
  165. # Отправляем SMS с кодом активации для подтверждения номера телефона
  166. $this->sms(false)->sendActivationCode($userData['phone_number'], $userData['activate_key']);
  167. $this->security->sessionStart();
  168. $this->security->setSESSION('users-register-data', array(
  169. 'id' => $userData['id'],
  170. 'name' => $userData['name'],
  171. 'password' => $pass,
  172. 'phone' => $userData['phone_number'],
  173. 'email' => $email,
  174. ));
  175.  
  176. $this->errors->set(_t('users', 'Данный аккаунт неактивирован. <a [link_activate]>Активировать</a>',
  177. array('link_activate'=>'href="'.static::url('register', array('step' => 'phone')).'"')));
  178. } else {
  179. $this->errors->set(_t('users', 'Данный аккаунт неактивирован, перейдите по ссылке отправленной вам в письме.<br /><a [link_resend]>Получить письмо повторно</a>',
  180. array('link_resend'=>'href="#" class="ajax j-resend-activation"')));
  181. }
  182. break;
  183. }
  184.  
  185. } while (false);
  186.  
  187. if ($aResponse['success']) {
  188. if (empty($back)
  189. || strpos($back, '/user/register') !== false
  190. || strpos($back, '/user/login') !== false
  191. ) {
  192. $back = bff::urlBase();
  193. }
  194. $aResponse['redirect'] = $back;
  195. }
  196.  
  197. $this->ajaxResponseForm($aResponse);
  198. } else {
  199. if (User::id()) {
  200. $this->redirectToCabinet();
  201. }
  202. }
  203.  
  204. # SEO
  205. $this->urlCorrection(static::url('login'));
  206. $this->setMeta('login');
  207.  
  208. return $this->authPage('auth.login', _t('users', 'Войдите на сайт с помощью электронной почты или через социальную сеть'), array(
  209. 'providers' => $this->social()->getProvidersEnabled()
  210. )
  211. );
  212. }
  213.  
  214. /**
  215. * Авторизация через соц. сети
  216. */
  217. public function loginSocial()
  218. {
  219. $this->social()->auth($this->input->get('provider', TYPE_NOTAGS));
  220. }
  221.  
  222. /**
  223. * Авторизация на фронтенде из админки
  224. */
  225. public function login_admin()
  226. {
  227. $userID = $this->input->get('uid', TYPE_UINT);
  228. do {
  229. if (!$this->security->validateReferer() || !$userID) break;
  230.  
  231. $userData = $this->model->userData($userID, array('last_login','email','password'));
  232. if (empty($userData)) break;
  233.  
  234. $hash = $this->input->get('hash', TYPE_STR);
  235. if (empty($hash)) break;
  236. if ($hash != $this->adminAuthURL($userID, $userData['last_login'], $userData['email'], true)) break;
  237.  
  238. if ($this->userAuth($userID, 'user_id', $userData['password']) !== true) break;
  239.  
  240. $this->redirect(bff::urlBase());
  241. } while (false);
  242.  
  243. $this->errors->error404();
  244. }
  245.  
  246. /**
  247. * Регистрация
  248. */
  249. public function register()
  250. {
  251. $this->setMeta('register');
  252.  
  253. switch ($this->input->getpost('step', TYPE_STR))
  254. {
  255. case 'phone': # Подтверждение номера телефона
  256. {
  257. if (User::id()) {
  258. $this->redirectToCabinet();
  259. }
  260. $registerData = $this->security->getSESSION('users-register-data');
  261. if (empty($registerData['id']) || empty($registerData['phone'])) {
  262. $this->errors->error404();
  263. }
  264. $userID = $registerData['id'];
  265. $userPhone = $registerData['phone'];
  266. $userData = $this->model->userData($userID, array('password','activated','activate_key','blocked','blocked_reason'));
  267. if (empty($userData) || $userData['blocked']) {
  268. $this->errors->error404();
  269. }
  270. if ($userData['activated']) {
  271. $this->userAuth($userID, 'user_id', $userData['password']);
  272. $this->redirectToCabinet();
  273. }
  274.  
  275. if (Request::isPOST())
  276. {
  277. $act = $this->input->postget('act');
  278. $response = array();
  279. if (!$this->security->validateReferer() || !static::registerPhone()) {
  280. $this->errors->reloadPage(); $act = '';
  281. }
  282. switch ($act)
  283. {
  284. # Проверка кода подтверждения
  285. case 'code-validate':
  286. {
  287. $code = $this->input->postget('code', TYPE_NOTAGS);
  288. if (mb_strtolower($code) !== $userData['activate_key']) {
  289. $this->errors->set(_t('users', 'Код подтверждения указан некорректно'), 'phone');
  290. break;
  291. }
  292. # Активируем аккаунт
  293. $res = $this->model->userSave($userID, array('phone_number_verified'=>1, 'activated' => 1, 'activate_key' => ''));
  294. if ($res) {
  295. bff::i()->callModules('onUserActivated', array($userID));
  296. # Авторизуем
  297. $this->userAuth($userID, 'user_id', $userData['password']);
  298. # Отправляем письмо об успешной регистрации
  299. bff::sendMailTemplate($registerData, 'users_register_phone', $registerData['email']);
  300. $this->security->setSESSION('users-register-data', null);
  301. $response['redirect'] = static::url('register', array('step' => 'finished'));
  302. } else {
  303. bff::log('users: Ошибка активации аккаунта пользователя по коду подтверждения [user-id="'.$userID.'"]');
  304. $this->errors->set(_t('users', 'Ошибка регистрации, обратитесь к администратору'));
  305. break;
  306. }
  307. } break;
  308. # Повторная отправка кода подтверждения
  309. case 'code-resend':
  310. {
  311. $activationData = $this->getActivationInfo();
  312.  
  313. $res = $this->sms()->sendActivationCode($userPhone, $activationData['key']);
  314. if ($res) {
  315. $activationData = $this->updateActivationKey($userID, $activationData['key']);
  316. if (!$activationData) {
  317. $this->errors->reloadPage();
  318. break;
  319. }
  320. }
  321. } break;
  322. # Смена номера телефона
  323. case 'phone-change':
  324. {
  325. $phone = $this->input->postget('phone', TYPE_NOTAGS, array('len'=>30));
  326. if (!$this->input->isPhoneNumber($phone)) {
  327. $this->errors->set(_t('users', 'Номер телефона указан некорректно'), 'phone');
  328. break;
  329. }
  330. if ($phone === $userPhone) {
  331. break;
  332. }
  333. if ($this->model->userPhoneExists($phone, $userID)) {
  334. $this->errors->set(_t('users', 'Пользователь с таким номером телефона уже зарегистрирован. <a [link_forgot]>Забыли пароль?</a>',
  335. array('link_forgot' => 'href="' . static::url('forgot') . '"')
  336. ), 'phone'
  337. );
  338. break;
  339. }
  340. $res = $this->model->userSave($userID, array(
  341. 'phone_number' => $phone,
  342. 'phone_number_verified' => 0,
  343. ));
  344. if (!$res) {
  345. bff::log('users: Ошибка обновления номера телефона [user-id="'.$userID.'"]');
  346. $this->errors->reloadPage();
  347. } else {
  348. $registerData['phone'] = $phone;
  349. $response['phone'] = '+'.$phone;
  350. $this->sms()->sendActivationCode($phone, $userData['activate_key']);
  351. $this->security->setSESSION('users-register-data', $registerData);
  352. }
  353. } break;
  354. }
  355.  
  356. $this->ajaxResponseForm($response);
  357. }
  358.  
  359. //
  360. return $this->authPage('auth.register.phone', _t('users', 'Подтверждение номера мобильного телефона'), $registerData);
  361. } break;
  362. case 'emailed': # Уведомление о письме "активации"
  363. {
  364. if (User::id()) {
  365. $this->redirectToCabinet();
  366. }
  367. $aData = $this->security->getSESSION('users-register-data');
  368. if (!empty($aData['id'])) {
  369. $aUser = $this->model->userData($aData['id'], array('activated', 'blocked','phone_number'));
  370. if (empty($aUser) || $aUser['activated'] || $aUser['blocked']) {
  371. $aData = false;
  372. }
  373. }
  374. if (static::registerPhone() && !empty($aUser['phone_number'])) {
  375. $this->errors->error404();
  376. }
  377. if (Request::isPOST()) {
  378. if (!$this->security->validateReferer()) {
  379. $this->errors->reloadPage();
  380. } else {
  381. if (!User::id() && !empty($aData)) {
  382. # Повторная отправка письма об успешной регистрации
  383. bff::sendMailTemplate($aData, 'users_register', $aData['email']);
  384. $this->security->setSESSION('users-register-data', null);
  385. }
  386. }
  387. $this->ajaxResponseForm();
  388. }
  389.  
  390. $bResend = $this->input->get('resend', TYPE_BOOL);
  391. $sTitle = ( $bResend ? _t('users', 'Письмо отправлено') : _t('users', 'Регистрация завершена') );
  392. return $this->authPage('auth.register.emailed', $sTitle, array('retry_allowed' => !empty($aData)));
  393. }
  394. break;
  395. case 'social': # Регистрация через аккаунт в соц. сети
  396. {
  397. if (User::id()) {
  398. if (Request::isPOST()) {
  399. $this->errors->reloadPage();
  400. $this->ajaxResponseForm();
  401. }
  402. $this->redirectToCabinet();
  403. }
  404.  
  405. $aSocialData = $this->social()->authData();
  406.  
  407. if (Request::isPOST()) {
  408. $aResponse = array('exists' => false);
  409. $p = $this->input->postm(array(
  410. 'email' => array(TYPE_NOTAGS, 'len' => 100), # E-mail
  411. 'agreement' => TYPE_BOOL, # Пользовательское соглашение
  412. )
  413. );
  414. extract($p);
  415. do {
  416. if (!$this->security->validateReferer() || empty($aSocialData)) {
  417. $this->errors->reloadPage();
  418. break;
  419. }
  420. if (!$this->input->isEmail($email)) {
  421. $this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
  422. break;
  423. }
  424. if ($mBanned = $this->checkBan(true, $email)) {
  425. $this->errors->set(_t('users', 'Доступ заблокирован по причине: [reason]', array('reason' => $mBanned)));
  426. break;
  427. }
  428. if ($this->model->userEmailExists($email)) {
  429. $aResponse['exists'] = true;
  430. break;
  431. }
  432. if (!$agreement) {
  433. $this->errors->set(_t('users', 'Пожалуйста подтвердите, что Вы согласны с пользовательским соглашением'), 'agreement');
  434. }
  435. if (!$this->errors->no()) {
  436. break;
  437. }
  438.  
  439. # Создаем аккаунт пользователя + генерируем пароль
  440. $aUserData = $this->userRegister(array(
  441. 'name' => $aSocialData['name'], # ФИО из соц. сети
  442. 'email' => $email, # E-mail
  443. )
  444. );
  445. if (empty($aUserData)) {
  446. $this->errors->set(_t('users', 'Ошибка регистрации, обратитесь к администратору'));
  447. break;
  448. }
  449. $nUserID = $aUserData['user_id'];
  450.  
  451. # Загружаем аватар из соц. сети
  452. if (!empty($aSocialData['avatar'])) {
  453. $this->avatar($nUserID)->uploadSocial($aSocialData['provider_id'], $aSocialData['avatar'], true);
  454. }
  455.  
  456. # Закрепляем соц. аккаунт за пользователем
  457. $this->social()->authFinish($nUserID);
  458.  
  459. # Активируем аккаунт пользователя без подтверждения email адреса
  460. if (!config::sys('users.register.social.email.activation', TYPE_BOOL))
  461. {
  462. $res = $this->model->userSave($nUserID, array(
  463. 'activated' => 1
  464. ));
  465. if (!$res) {
  466. $this->errors->reloadPage(); break;
  467. }
  468.  
  469. $res = $this->userAuth($nUserID, 'user_id', $aUserData['password'], false);
  470. if ($res!==true) {
  471. $this->errors->reloadPage(); break;
  472. }
  473.  
  474. # Отправляем письмо об успешной регистрации
  475. $aMailData = array(
  476. 'name' => $aSocialData['name'],
  477. 'password' => $aUserData['password'],
  478. 'email' => $email,
  479. );
  480. bff::sendMailTemplate($aMailData, 'users_register_auto', $email);
  481.  
  482. $aResponse['success'] = true;
  483. $aResponse['redirect'] = static::url('register', array('step' => 'finished'));
  484. break;
  485. }
  486.  
  487. # Отправляем письмо для активации аккаунта
  488. $aMailData = array(
  489. 'id' => $nUserID,
  490. 'name' => $aSocialData['name'],
  491. 'password' => $aUserData['password'],
  492. 'email' => $email,
  493. 'activate_link' => $aUserData['activate_link']
  494. );
  495. bff::sendMailTemplate($aMailData, 'users_register', $email);
  496.  
  497. # Сохраняем данные для повторной отправки письма
  498. $this->security->sessionStart();
  499. $this->security->setSESSION('users-register-data', $aMailData);
  500.  
  501. $aResponse['success'] = true;
  502. $aResponse['redirect'] = static::url('register', array('step' => 'emailed')); # url результирующей страницы
  503.  
  504. } while (false);
  505.  
  506. $this->ajaxResponseForm($aResponse);
  507. }
  508.  
  509. # Данные о процессе регистрации через соц.сеть некорректны, причины:
  510. # 1) неудалось сохранить в сессии
  511. # 2) повторная попытка, вслед за успешной (случайный переход по ссылке)
  512. if (empty($aSocialData)) {
  513. $this->redirect(static::url('register'));
  514. }
  515.  
  516. # Аватар по-умолчанию
  517. if (empty($aSocialData['avatar'])) {
  518. $aSocialData['avatar'] = UsersAvatar::url(0, '', UsersAvatar::szNormal);
  519. }
  520.  
  521. return $this->authPage('auth.register.social', _t('users', 'Для завершения регистрации введите Вашу электронную почту'), $aSocialData);
  522. }
  523. break;
  524. case 'finished': # Страница успешной регистрации
  525. {
  526. return $this->authPage('auth.message', _t('users', 'Вы успешно зарегистрировались!'), array(
  527. 'message' => _t('users', 'Теперь вы можете <a [link_home]>перейти на главную страницу</a> или <a [link_profile]>в настройки своего профиля</a>.',
  528. array(
  529. 'link_home' => 'href="' . bff::urlBase() . '"',
  530. 'link_profile' => 'href="' . static::url('my.settings') . '"'
  531. )
  532. )
  533. )
  534. );
  535. }
  536. break;
  537. }
  538.  
  539. $bPhone = static::registerPhone(); # задействовать: номер телефона
  540. $bCaptcha = (bool)config::sys('users.register.captcha', TYPE_BOOL); # задействовать: капчу
  541. $bPasswordConfirm = (bool)config::sys('users.register.passconfirm', true, TYPE_BOOL); # задействовать: подтверждение пароля
  542.  
  543. if (Request::isPOST()) {
  544. $aResponse = array('captcha' => false);
  545.  
  546. if (User::id()) {
  547. $this->ajaxResponseForm($aResponse);
  548. }
  549.  
  550. $aData = $this->input->postm(array(
  551. 'phone' => array(TYPE_NOTAGS, 'len' => 30), # Номер телефона
  552. 'email' => array(TYPE_NOTAGS, 'len' => 100), # E-mail
  553. 'pass' => TYPE_NOTRIM, # Пароль
  554. 'pass2' => TYPE_NOTRIM, # Подтверждение пароля
  555. 'back' => TYPE_NOTAGS, # Ссылка возврата
  556. 'captcha' => TYPE_STR, # Капча
  557. 'agreement' => TYPE_BOOL, # Пользовательское соглашение
  558. )
  559. );
  560. extract($aData);
  561.  
  562. $aResponse['back'] = $back;
  563.  
  564. do {
  565. if (!$this->security->validateReferer()) {
  566. $this->errors->reloadPage();
  567. break;
  568. }
  569.  
  570. if ($bPhone && ! $this->input->isPhoneNumber($phone)) {
  571. $this->errors->set(_t('users', 'Номер телефона указан некорректно'), 'phone');
  572. break;
  573. }
  574.  
  575. if (!$this->input->isEmail($email)) {
  576. $this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
  577. break;
  578. }
  579.  
  580. if ($mBanned = $this->checkBan(true, $email)) {
  581. $this->errors->set(_t('users', 'Доступ заблокирован по причине: [reason]', array('reason' => $mBanned)));
  582. break;
  583. }
  584.  
  585. if ($bPhone && $this->model->userPhoneExists($phone)) {
  586. $this->errors->set(_t('users', 'Пользователь с таким номером телефона уже зарегистрирован. <a [link_forgot]>Забыли пароль?</a>',
  587. array('link_forgot' => 'href="' . static::url('forgot') . '"')
  588. ), 'phone'
  589. );
  590. break;
  591. }
  592.  
  593. if ($this->model->userEmailExists($email)) {
  594. $this->errors->set(_t('users', 'Пользователь с таким e-mail адресом уже зарегистрирован. <a [link_forgot]>Забыли пароль?</a>',
  595. array('link_forgot' => 'href="' . static::url('forgot') . '"')
  596. ), 'email'
  597. );
  598. break;
  599. }
  600.  
  601. if (empty($pass)) {
  602. $this->errors->set(_t('users', 'Укажите пароль'), 'pass');
  603. } elseif (mb_strlen($pass) < $this->passwordMinLength) {
  604. $this->errors->set(_t('users', 'Пароль не должен быть короче [min] символов', array('min' => $this->passwordMinLength)), 'pass');
  605. } else {
  606. if ($bPasswordConfirm && $pass != $pass2) {
  607. $this->errors->set(_t('users', 'Подтверждение пароля указано неверно'), 'pass2');
  608. }
  609. }
  610.  
  611. if ($bCaptcha) {
  612. $oProtection = new CCaptchaProtection();
  613. if (empty($captcha) || !$oProtection->valid($this->input->cookie('c2'), $captcha)) {
  614. $this->errors->set(_t('users', 'Результат с картинки указан некорректно'), 'captcha');
  615. $aResponse['captcha'] = true;
  616. Request::deleteCOOKIE('c2');
  617. }
  618. }
  619.  
  620. if (!$agreement) {
  621. $this->errors->set(_t('users', 'Пожалуйста подтвердите, что Вы согласны с пользовательским соглашением'), 'agreement');
  622. }
  623.  
  624. # не чаще чем раз в {X} секунд с одного IP (для одного пользователя)
  625. if ($this->errors->no()) {
  626. Site::i()->preventSpam('users-register', 30);
  627. }
  628.  
  629. if (!$this->errors->no()) {
  630. break;
  631. }
  632.  
  633. # Создаем аккаунт пользователя
  634. $aUserData = array(
  635. 'email' => $email,
  636. 'password' => $pass,
  637. );
  638. if ($bPhone) {
  639. $aUserData['phone_number'] = $phone;
  640. }
  641. $aUserData = $this->userRegister($aUserData);
  642. if (empty($aUserData)) {
  643. $this->errors->set(_t('users', 'Ошибка регистрации, обратитесь к администратору'));
  644. break;
  645. }
  646.  
  647. $aResponse['success'] = true;
  648. $aResponse['redirect'] = static::url('register', array('step' => ($bPhone?'phone':'emailed'))); # url результирующей страницы
  649.  
  650. # Отправляем письмо для активации аккаунта
  651. $aMailData = array(
  652. 'id' => $aUserData['user_id'],
  653. 'name' => '',
  654. 'password' => $pass,
  655. 'phone' => $phone,
  656. 'email' => $email,
  657. 'activate_link' => $aUserData['activate_link']
  658. );
  659. if ($bPhone) {
  660. # Отправляем SMS с кодом активации для подтверждения номера телефона
  661. # Письмо отправим после успешного подтверждения
  662. $this->sms(false)->sendActivationCode($phone, $aUserData['activate_key']);
  663. } else {
  664. bff::sendMailTemplate($aMailData, 'users_register', $email);
  665. }
  666.  
  667. # Сохраняем данные для повторной отправки письма
  668. $this->security->sessionStart();
  669. $this->security->setSESSION('users-register-data', $aMailData);
  670.  
  671. } while (false);
  672.  
  673. $this->ajaxResponseForm($aResponse);
  674. } else {
  675. if (User::id()) {
  676. $this->redirectToCabinet();
  677. }
  678. }
  679.  
  680. # seo
  681. $this->urlCorrection(static::url('register'));
  682.  
  683. return $this->authPage('auth.register', _t('users', 'Зарегистрируйтесь на сайте с помощью электронной почты или через социальную сеть'), array(
  684. 'phone_on' => $bPhone,
  685. 'captcha_on' => $bCaptcha,
  686. 'pass_confirm_on' => $bPasswordConfirm,
  687. 'providers' => $this->social()->getProvidersEnabled()
  688. )
  689. );
  690. }
  691.  
  692. /**
  693. * Активация пользователя
  694. */
  695. public function activate()
  696. {
  697. if (User::id()) {
  698. $this->redirectToCabinet();
  699. }
  700.  
  701. # ключ активации
  702. $sKey = $this->input->get('key', TYPE_STR);
  703.  
  704. # ключ переписки
  705. $bMessageRedirect = false;
  706. $sMessageKey = $this->input->get('msg', TYPE_NOTAGS);
  707. if (!empty($sMessageKey)) {
  708. list($nAuthorID, $nInterlocutorID) = explode('-', (strpos($sMessageKey, '-') !== false ? $sMessageKey : '0-0-0'), 3);
  709. $nAuthorID = intval($nAuthorID);
  710. $nInterlocutorID = intval($nInterlocutorID);
  711. $bMessageRedirect = ($nAuthorID > 0 && $nInterlocutorID > 0);
  712. }
  713.  
  714. $bAutoRegistration = ($bMessageRedirect || $this->input->get('ar', TYPE_BOOL));
  715.  
  716. $aUserData = $this->model->userDataByFilter(array(
  717. 'activated' => 0,
  718. 'blocked' => 0,
  719. array('activate_expire > :expire', ':expire' => $this->db->now()),
  720. 'activate_key' => $sKey,
  721. ), array('user_id', 'email', 'password', 'password_salt', 'name', 'activated')
  722. );
  723.  
  724. # Не нашли пользователя по ключу:
  725. # 1) Срок ключа истек / ключ некорректный
  726. # 2) Пользователь активирован / заблокирован
  727. if (empty($aUserData)) {
  728. # При переходе по ссылке "прочитать сообщение..."
  729. if ($bMessageRedirect) {
  730. return $this->authPage('auth.message', _t('users', 'Просмотр переписки'), array(
  731. 'message' => _t('users', 'Для просмотра переписки необходимо <a [link_auth]>авторизоваться</a>.', array(
  732. 'link_auth' => ' href="' . static::url('login') . '"'
  733. )
  734. )
  735. )
  736. );
  737. }
  738.  
  739. return $this->authPage('auth.message', _t('users', 'Активация аккаунта'), array(
  740. 'message' => _t('users', 'Срок действия ключа активации истек.')
  741. )
  742. );
  743. }
  744.  
  745. $nUserID = $aUserData['user_id'];
  746.  
  747. # Активируем
  748. $aActivateData = array(
  749. 'activated' => 1,
  750. 'activate_key' => '',
  751. );
  752. if ($bAutoRegistration) {
  753. $sPassword = func::generator(12); # генерируем новый пароль
  754. $aActivateData['password'] = $aUserData['password'] = $this->security->getUserPasswordMD5($sPassword, $aUserData['password_salt']);
  755. }
  756. $bActivated = $this->model->userSave($nUserID, $aActivateData);
  757. if ($bActivated) {
  758. # Триггер активации аккаунта
  759. bff::i()->callModules('onUserActivated', array($nUserID));
  760.  
  761. # Отправляем письмо об успешной автоматической регистрации
  762. if ($bAutoRegistration) {
  763. bff::sendMailTemplate(array(
  764. 'name' => $aUserData['name'],
  765. 'email' => $aUserData['email'],
  766. 'password' => $sPassword
  767. ),
  768. 'users_register_auto', $aUserData['email']
  769. );
  770. }
  771. }
  772.  
  773. # Авторизуем
  774. $bAuthorized = $this->userAuth($nUserID, 'user_id', $aUserData['password']);
  775. if ($bAuthorized === true) {
  776. # Пересохраняем избранные ОБ из куков в базу
  777. BBS::i()->saveFavoritesToDB($nUserID);
  778.  
  779. # Редирект на переписку
  780. if ($bMessageRedirect) {
  781. $aInterlocutorData = $this->model->userData($nInterlocutorID, array('user_id', 'login'));
  782. if (!empty($aInterlocutorData)) {
  783. $this->redirect(InternalMail::url('my.messages', array('i' => $aInterlocutorData['login'])));
  784. }
  785. }
  786. }
  787.  
  788. # Редирект на страницу успешного завершения регистрации
  789. $this->redirect(static::url('register', array('step' => 'finished')));
  790. }
  791.  
  792. /**
  793. * Восстановление пароля пользователя
  794. */
  795. public function forgot()
  796. {
  797. # Уже авторизован
  798. if (User::id()) {
  799. if (Request::isAJAX()) {
  800. $this->errors->impossible();
  801. $this->ajaxResponseForm();
  802. }
  803. $this->redirectToCabinet();
  804. }
  805.  
  806. $sKey = $this->input->getpost('key', TYPE_STR, array('len' => 100));
  807. $bSocial = $this->input->getpost('social', TYPE_BOOL);
  808. if (!empty($sKey)) {
  809. # Шаг2: Смена пароля
  810. if (Request::isAJAX()) {
  811. do {
  812. if (!$this->security->validateReferer()) {
  813. $this->errors->reloadPage();
  814. break;
  815. }
  816. # Ищем по "ключу восстановления"
  817. $aData = $this->model->userDataByFilter(array(
  818. 'blocked' => 0, # незаблокированные аккаунты
  819. 'activate_key' => $sKey,
  820. array('activate_expire > :expire', ':expire' => $this->db->now()),
  821. ), array('user_id', 'email', 'password', 'password_salt', 'activated')
  822. );
  823.  
  824. # Не нашли, возможные причины:
  825. # 1) Истек срок действия ссылки восстановления / неверная ссылка восстановления
  826. # 2) Аккаунт заблокирован
  827. if (empty($aData)) {
  828. $this->errors->set(_t('users', 'Срок действия ссылки восстановления пароля истек или ссылка некорректна, <a href="[link_fogot]">повторите попытку</a>.',
  829. array('link_fogot' => static::url('forgot'))
  830. )
  831. );
  832. break;
  833. }
  834.  
  835. # Проверяем новый пароль
  836. $password = $this->input->post('pass', TYPE_NOTRIM);
  837. if (mb_strlen($password) < $this->passwordMinLength) {
  838. $this->errors->set(_t('users', 'Пароль не должен быть короче [min] символов', array('min' => $this->passwordMinLength)), 'pass');
  839. break;
  840. }
  841.  
  842. $nUserID = $aData['user_id'];
  843.  
  844. # Cохраняем новый пароль + активируем
  845. $this->model->userSave($nUserID, array(
  846. 'password' => $this->security->getUserPasswordMD5($password, $aData['password_salt']),
  847. 'activated' => 1, # активируем, если аккаунт еще НЕ активирован
  848. 'activate_key' => '', # сбрасываем ключ
  849. ));
  850.  
  851. # Закрепляем соц. аккаунт за профилем
  852. if ($bSocial) {
  853. $this->social()->authFinish($nUserID);
  854. }
  855.  
  856. } while (false);
  857.  
  858. $this->ajaxResponseForm();
  859. }
  860.  
  861. return $this->authPage('auth.forgot.finish', _t('users', 'Введите новый пароль'), array(
  862. 'key' => $sKey,
  863. 'social' => $bSocial,
  864. )
  865. );
  866. } else {
  867. # Шаг1: Инициация восстановления пароля по E-mail адресу
  868. if (Request::isAJAX()) {
  869. $email = $this->input->post('email', TYPE_STR);
  870. do {
  871. if (!$this->security->validateReferer()) {
  872. $this->errors->reloadPage();
  873. break;
  874. }
  875. # Проверяем E-mail
  876. if (!$this->input->isEmail($email)) {
  877. $this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
  878. break;
  879. }
  880. # Получаем данные пользователя
  881. # - восстановление пароля для неактивированных аккаунтов допустимо
  882. $aData = $this->model->userDataByFilter(array('email' => $email, 'blocked' => 0),
  883. array('user_id', 'name', 'activated', 'activate_expire')
  884. );
  885. if (empty($aData)) {
  886. $this->errors->set(_t('users', 'Указанный e-mail в базе не найден'), 'email');
  887. break;
  888. }
  889.  
  890. /**
  891. * Генерируем "ключ восстановления", помечаем период его действия.
  892. * В случае если аккаунт неактивирован, период действия ключа восстановления пароля будет равен
  893. * периоду действия ссылки активации аккаунта, поскольку задействуется
  894. * одно и тоже поле "activate_expire"
  895. */
  896. $sKey = func::generator(20);
  897. $bSaved = $this->model->userSave($aData['user_id'], array(
  898. 'activate_key' => $sKey,
  899. 'activate_expire' => (!$aData['activated'] ? $aData['activate_expire'] :
  900. date('Y-m-d H:i:s', strtotime('+4 hours'))),
  901. )
  902. );
  903.  
  904. if (!$bSaved) {
  905. $this->errors->reloadPage();
  906. } else {
  907. # Отправляем письмо с инcтрукцией о смене пароля
  908. bff::sendMailTemplate(array(
  909. 'link' => static::url('forgot', array('key' => $sKey, 'social' => $bSocial)),
  910. 'email' => $email,
  911. 'name' => $aData['name']
  912. ), 'users_forgot_start', $email
  913. );
  914. }
  915. } while (false);
  916.  
  917. $this->ajaxResponseForm();
  918. }
  919.  
  920. # seo
  921. $this->urlCorrection(static::url('forgot'));
  922. $this->setMeta('forgot');
  923.  
  924. return $this->authPage('auth.forgot.start', _t('users', 'Введите электронную почту, которую вы указывали при регистрации'), array(
  925. 'social' => $bSocial,
  926. )
  927. );
  928. }
  929. }
  930.  
  931. /**
  932. * Выход
  933. */
  934. public function logout()
  935. {
  936. $sRedirect = bff::urlBase();
  937.  
  938. if (User::id()) {
  939. $sReferer = Request::referer();
  940.  
  941. # оставляем пользователя на текущей странице,
  942. # за исключением следующих:
  943. $aWrongReferers = array(
  944. '/user/login',
  945. '/user/register',
  946. '/cabinet/',
  947. '/item/edit',
  948. '/item/success',
  949. '/item/activate',
  950. );
  951.  
  952. if (!empty($sReferer)) {
  953. foreach ($aWrongReferers as $v) {
  954. if (strpos($sReferer, $v) !== false) {
  955. $sReferer = false;
  956. break;
  957. }
  958. }
  959. if (!empty($sReferer)) {
  960. $sRedirect = $sReferer;
  961. }
  962. }
  963.  
  964. if ($this->security->validateReferer()) {
  965. $this->security->sessionDestroy(-1, true);
  966.  
  967. }
  968. }
  969.  
  970. $this->redirect($sRedirect);
  971. }
  972.  
  973. /**
  974. * Профиль пользователя
  975. */
  976. public function profile()
  977. {
  978. $login = $this->input->get('login', TYPE_STR);
  979.  
  980. # Данные пользователя
  981. $user = $this->model->userDataByFilter(array('login' => $login), array(
  982. 'user_id',
  983. 'user_id_ex',
  984. 'shop_id',
  985. 'name',
  986. 'login',
  987. 'sex',
  988. 'activated',
  989. 'blocked',
  990. 'blocked_reason',
  991. 'avatar',
  992. 'created',
  993. 'region_id',
  994. 'reg1_country',
  995. 'phone_number',
  996. 'phone_number_verified',
  997. 'phones',
  998. 'skype',
  999. 'icq'
  1000. )
  1001. );
  1002.  
  1003. if (empty($user)) {
  1004. $this->errors->error404();
  1005. }
  1006. if ($user['blocked']) {
  1007. return $this->showInlineMessage(_t('users', 'Аккаунт пользователя был заблокирован по причине:<br /><b>[reason]</b>',
  1008. array('reason' => $user['blocked_reason'])
  1009. )
  1010. );
  1011. }
  1012.  
  1013. # Подготовка данных
  1014. $userID = $user['user_id'];
  1015. if (empty($user['name'])) {
  1016. $user['name'] = $user['login'];
  1017. }
  1018. $user['avatar'] = UsersAvatar::url($userID, $user['avatar'], UsersAvatar::szNormal, $user['sex']);
  1019. if (!empty($user['region_id'])) {
  1020. $user['region_title'] = Geo::regionTitle($user['region_id']);
  1021. # разворачиваем данные о регионе: region_id => reg1_country, reg2_region, reg3_city
  1022. $aRegions = Geo::model()->regionParents($user['region_id']);
  1023. $user = array_merge($user, $aRegions['db']);
  1024. $user['country_title'] = Geo::regionTitle($user['reg1_country']);
  1025. }
  1026. $user['phones'] = (!empty($user['phones']) ? func::unserialize($user['phones']) : array());
  1027. if (static::registerPhoneContacts() && $user['phone_number'] && $user['phone_number_verified']) {
  1028. array_unshift($user['phones'], array('v'=>$user['phone_number'],'m'=>mb_substr($user['phone_number'], 0, 2) . 'x xxx xxxx'));
  1029. }
  1030. $user['skype'] = (!empty($user['skype']) ? mb_substr($user['skype'], 0, 2) . 'xxxxx' : '');
  1031. $user['icq'] = (!empty($user['icq']) ? mb_substr($user['icq'], 0, 2) . 'xxxxx' : '');
  1032. $user['has_contacts'] = ($user['phones'] || $user['skype'] || $user['icq']);
  1033.  
  1034. # Разделы профиля
  1035. $tab = trim($this->input->getpost('tab', TYPE_NOTAGS), ' /');
  1036. $tabs = array(
  1037. 'items' => array(
  1038. 't' => _t('users', 'Объявления пользователя'),
  1039. 'm' => 'BBS',
  1040. 'ev' => 'user_items',
  1041. 'url' => static::urlProfile($user['login']),
  1042. 'a' => false
  1043. ),
  1044. );
  1045. if (!isset($tabs[$tab])) {
  1046. $tab = 'items';
  1047. }
  1048. $tabs[$tab]['a'] = true;
  1049. $user['profile_link'] = static::urlProfile($login);
  1050. $user['profile_link_dynamic'] = static::urlProfile($login, '', array(), true);
  1051.  
  1052. $data = array(
  1053. 'content' => call_user_func(array(bff::module($tabs[$tab]['m']), $tabs[$tab]['ev']), $userID, $user),
  1054. 'tabs' => &$tabs,
  1055. 'user' => &$user,
  1056. 'is_owner' => User::isCurrent($userID),
  1057. );
  1058.  
  1059. return $this->viewPHP($data, 'profile');
  1060. }
  1061.  
  1062. /**
  1063. * Кабинет пользователя (layout)
  1064. */
  1065. public function my()
  1066. {
  1067. $aData = array('shop_open' => false);
  1068. $tab = $this->input->get('tab', TYPE_NOTAGS);
  1069. $header = $this->my_header_menu();
  1070. $counters = User::counter(array());
  1071. $balance = User::balance();
  1072. $shopID = User::shopID();
  1073. $publisher = BBS::publisher();
  1074. $tabs = array();
  1075.  
  1076. # Магазин
  1077. if (isset($header['menu']['shop'])) {
  1078. $tabs['shop'] = array(
  1079. 't' => _t('users', 'Магазин'),
  1080. 'm' => 'Shops',
  1081. 'ev' => 'my_shop',
  1082. 'url' => Shops::url('my.shop'),
  1083. );
  1084. if ($tab == 'shop/open') {
  1085. $this->redirect($tabs['shop']['url']);
  1086. }
  1087. }
  1088.  
  1089. # Объявления
  1090. if (isset($header['menu']['items'])) {
  1091. $tabs['items'] = array(
  1092. 't' => ($publisher == BBS::PUBLISHER_USER || !$shopID ?
  1093. _t('users', 'Объявления') :
  1094. _t('users', 'Частные объявления')
  1095. ),
  1096. 'm' => 'BBS',
  1097. 'url' => BBS::url('my.items')
  1098. );
  1099. if ($tab == 'shop' && !isset($tabs['shop'])) {
  1100. $this->redirect($tabs['items']['url']);
  1101. }
  1102. } else {
  1103. if ($tab == 'items') {
  1104. $this->redirect($tabs['shop']['url']);
  1105. }
  1106. }
  1107.  
  1108. # Импорт
  1109. if(BBS::importAllowed()){
  1110. $tabs['import'] = array(
  1111. 't' => _t('users', 'Импорт'),
  1112. 'm' => 'BBS',
  1113. 'ev' => 'my_import',
  1114. 'url' => BBS::url('my.import'),
  1115. );
  1116. }
  1117.  
  1118. # Избранные объявления
  1119. $tabs['favs'] = array(
  1120. 't' => _t('users', 'Избранные'),
  1121. 'm' => 'BBS',
  1122. 'url' => BBS::url('my.favs'),
  1123. );
  1124. # Сообщения
  1125. $tabs['messages'] = array(
  1126. 't' => _t('users', 'Сообщения'),
  1127. 'm' => 'InternalMail',
  1128. 'url' => InternalMail::url('my.messages'),
  1129. 'counter' => (!empty($counters['cnt_internalmail_new']) ?
  1130. '<span class="u-cabinet__main-navigation__new-message"> +' . $counters['cnt_internalmail_new'] . '</span>' :
  1131. ''),
  1132. );
  1133. $tabs['messages/chat'] = array('t' => false, 'm' => 'InternalMail', 'ev' => 'my_chat');
  1134.  
  1135. # Счет
  1136. if (bff::servicesEnabled()) {
  1137. $tabs['bill'] = array(
  1138. 't' => _t('users', 'Счёт'),
  1139. 'm' => 'Bills',
  1140. 'url' => Bills::url('my.history'),
  1141. 'counter' => (!empty($balance) ?
  1142. '<span class="u-cabinet__main-navigation__money"> (' . $balance . ' ' . Site::currencyDefault() . ')</span>' :
  1143. ''),
  1144. );
  1145. }
  1146. # Настройки
  1147. $tabs['settings'] = array(
  1148. 't' => _t('users', 'Настройки'),
  1149. 'm' => 'Users',
  1150. 'url' => Users::url('my.settings'),
  1151. );
  1152. # Открыть магазин
  1153. if (!$shopID && bff::shopsEnabled()) {
  1154. $aData['shop_open'] = array('url' => Shops::url('my.open'), 'active' => ($tab == 'shop/open'));
  1155. $tabs['shop/open'] = array(
  1156. 't' => false,
  1157. 'm' => 'Shops',
  1158. 'ev' => 'my_open',
  1159. 'url' => $aData['shop_open']['url']
  1160. );
  1161. }
  1162.  
  1163. if (!isset($tabs[$tab])) {
  1164. if (Request::isAJAX()) {
  1165. $this->errors->impossible();
  1166. $this->ajaxResponseForm();
  1167. } else {
  1168. $this->errors->error404();
  1169. }
  1170. }
  1171. if (!User::id()) {
  1172. if (Request::isAJAX() && $tab != 'favs') {
  1173. $this->errors->reloadPage();
  1174. $this->ajaxResponseForm();
  1175. }
  1176. }
  1177.  
  1178. $aData['content'] = call_user_func(array(
  1179. bff::module($tabs[$tab]['m']),
  1180. (isset($tabs[$tab]['ev']) ? $tabs[$tab]['ev'] : 'my_' . $tab)
  1181. )
  1182. );
  1183.  
  1184. if ($tab == 'messages/chat') {
  1185. $tab = 'messages';
  1186. }
  1187. $tabs[$tab]['active'] = true;
  1188.  
  1189. $aData += array(
  1190. 'tabs' => &$tabs,
  1191. 'tab' => $tab,
  1192. 'user' => User::data(array('name', 'shop_id')),
  1193. );
  1194.  
  1195. $this->seo()->robotsIndex(false);
  1196. bff::setMeta(_t('users', 'Кабинет пользователя'));
  1197.  
  1198. return $this->viewPHP($aData, 'my.layout');
  1199. }
  1200.  
  1201. /**
  1202. * Кабинет: Настройки профиля
  1203. */
  1204. public function my_settings()
  1205. {
  1206. $nUserID = User::id();
  1207. $nShopID = User::shopID();
  1208. $nPublisher = BBS::publisher();
  1209. if (!$nUserID) {
  1210. return $this->showInlineMessage(_t('users', 'Для доступа в кабинет необходимо авторизоваться'), array('auth' => true));
  1211. }
  1212.  
  1213. $this->security->setTokenPrefix('my-settings');
  1214. # доступность настроек:
  1215. # true - доступна, false - скрыта
  1216. $on_contacts = (bool)config::sys('users.settings.contacts', true, TYPE_BOOL); # контактные данные
  1217. $on_email = (bool)config::sys('users.settings.email.change', true, TYPE_BOOL); # смена email-адреса
  1218. $on_phone = static::registerPhone(); # смена номера телефона
  1219. $on_destroy = (bool)config::sys('users.settings.destroy', TYPE_BOOL); # удаление аккаунта
  1220.  
  1221. # скрываем настройки контактов пользователя при включенном обязательном магазине (не в статусе заявки)
  1222. if ($nShopID && ($nPublisher == BBS::PUBLISHER_SHOP || $nPublisher == BBS::PUBLISHER_USER_TO_SHOP)) {
  1223. if (Shops::premoderation()) {
  1224. $aShopData = Shops::model()->shopData($nShopID, array('status'));
  1225. if (!empty($aShopData['status']) && $aShopData['status'] != Shops::STATUS_REQUEST) {
  1226. $on_contacts = false;
  1227. }
  1228. } else {
  1229. $on_contacts = false;
  1230. }
  1231. }
  1232.  
  1233. if (Request::isPOST()) {
  1234. $sAction = $this->input->getpost('act', TYPE_STR);
  1235. if (!$this->security->validateToken() && $sAction != 'avatar-upload') {
  1236. $this->errors->reloadPage();
  1237. $this->ajaxResponseForm();
  1238. }
  1239.  
  1240. $aResponse = array();
  1241. switch ($sAction) {
  1242. case 'shop': # магазин
  1243. {
  1244. if (!User::shopID() || !bff::shopsEnabled()) {
  1245. $this->errors->reloadPage();
  1246. break;
  1247. }
  1248.  
  1249. Shops::i()->my_settings();
  1250. }
  1251. break;
  1252. case 'contacts': # контактные данные
  1253. {
  1254. if (!$on_contacts) {
  1255. $this->errors->reloadPage();
  1256. break;
  1257. }
  1258.  
  1259. $aData = $this->input->postm(array(
  1260. 'name' => array(TYPE_NOTAGS, 'len' => 50), # ФИО
  1261. 'region_id' => TYPE_UINT, # город или 0
  1262. 'addr_addr' => array(TYPE_NOTAGS, 'len' => 400), # адрес
  1263. 'addr_lat' => TYPE_NUM, # адрес, координата LAT
  1264. 'addr_lon' => TYPE_NUM, # адрес, координата LON
  1265. 'phones' => TYPE_ARRAY_NOTAGS, # телефоны
  1266. 'skype' => array(TYPE_NOTAGS, 'len' => 32), # skype
  1267. 'icq' => array(TYPE_NOTAGS, 'len' => 50), # icq
  1268. )
  1269. );
  1270.  
  1271. $this->cleanUserData($aData);
  1272.  
  1273. $this->model->userSave($nUserID, $aData);
  1274.  
  1275. $this->security->updateUserInfo($aData);
  1276.  
  1277. $aResponse['name'] = $aData['name'];
  1278.  
  1279. }
  1280. break;
  1281. case 'avatar-upload': # аватар: загрузка
  1282. {
  1283. if (!$this->security->validateToken()) {
  1284. $this->errors->reloadPage();
  1285. $mResult = false;
  1286. } else {
  1287. $mResult = $this->avatar($nUserID)->uploadQQ(true, true);
  1288. }
  1289.  
  1290. $aResponse = array(
  1291. 'success' => ($mResult !== false && $this->errors->no()),
  1292. 'errors' => $this->errors->get(),
  1293. );
  1294. if ($mResult !== false) {
  1295. $this->security->updateUserInfo(array('avatar' => $mResult['filename']));
  1296. $nSex = User::data('sex');
  1297. $aResponse = array_merge($aResponse, $mResult);
  1298. foreach (array(UsersAvatar::szNormal, UsersAvatar::szSmall) as $size) {
  1299. $aResponse[$size] = UsersAvatar::url($nUserID, $mResult['filename'], $size, $nSex);
  1300. }
  1301. }
  1302.  
  1303. $this->ajaxResponse($aResponse, true, false);
  1304. }
  1305. break;
  1306. case 'avatar-delete': # аватар: удаление
  1307. {
  1308. $bDeleted = $this->avatar($nUserID)->delete(true);
  1309. if ($bDeleted) {
  1310. $nSex = User::data('sex');
  1311. $aResponse[UsersAvatar::szNormal] = UsersAvatar::url(0, false, UsersAvatar::szNormal, $nSex);
  1312. $aResponse[UsersAvatar::szSmall] = UsersAvatar::url(0, false, UsersAvatar::szSmall, $nSex);
  1313. $this->security->updateUserInfo(array('avatar' => ''));
  1314. }
  1315. }
  1316. break;
  1317. case 'social-unlink': # соц. сети: отвязывание
  1318. {
  1319. $oSocial = $this->social();
  1320. $providerKey = $this->input->post('provider', TYPE_STR);
  1321. $providerID = $oSocial->getProviderID($providerKey);
  1322. if ($providerID) {
  1323. $res = $oSocial->unlinkSocialAccountFromUser($providerID, $nUserID);
  1324. if (!$res) {
  1325. $this->errors->reloadPage();
  1326. }
  1327. }
  1328. }
  1329. break;
  1330. case 'enotify': # email уведомления
  1331. {
  1332. $aUserEnotify = $this->input->post('enotify', TYPE_ARRAY_UINT);
  1333. $res = $this->model->userSave($nUserID, array('enotify' => array_sum($aUserEnotify)));
  1334. if (empty($res)) {
  1335. $this->errors->reloadPage();
  1336. }
  1337. }
  1338. break;
  1339. case 'pass': # смена пароля
  1340. {
  1341. $this->input->postm(array(
  1342. 'pass0' => TYPE_NOTRIM, # текущий пароль
  1343. 'pass1' => TYPE_NOTRIM, # новый пароль
  1344. ), $p
  1345. );
  1346. extract($p, EXTR_REFS);
  1347.  
  1348. if (!User::isCurrentPassword($pass0)) {
  1349. $this->errors->set(_t('users', 'Текущий пароль указан некорректно'), 'pass0');
  1350. break;
  1351. }
  1352.  
  1353. if (empty($pass1)) {
  1354. $this->errors->set(_t('users', 'Укажите новый пароль'), 'pass1');
  1355. } elseif (mb_strlen($pass1) < $this->passwordMinLength) {
  1356. $this->errors->set(_t('users', 'Новый пароль не должен быть короче [symbols] символов',
  1357. array('symbols' => $this->passwordMinLength)
  1358. ), 'pass1'
  1359. );
  1360. } elseif ($pass0 == $pass1) {
  1361. $this->errors->set(_t('users', 'Новый пароль не должен совпадать с текущим'), 'pass1');
  1362. }
  1363.  
  1364. if (!$this->errors->no()) {
  1365. break;
  1366. }
  1367.  
  1368. $sNewPasswordHash = $this->security->getUserPasswordMD5($pass1, User::data('password_salt'));
  1369. $res = $this->model->userSave($nUserID, array('password' => $sNewPasswordHash));
  1370. if (!empty($res)) {
  1371. $this->security->updateUserInfo(array('password' => $sNewPasswordHash));
  1372. } else {
  1373. $this->errors->reloadPage();
  1374. }
  1375. }
  1376. break;
  1377. case 'phone': # смена номера телефона
  1378. {
  1379. if (!$on_phone) {
  1380. $this->errors->reloadPage();
  1381. break;
  1382. }
  1383. $this->input->postm(array(
  1384. 'phone' => array(TYPE_NOTAGS, 'len' => 30), # новый номер телефона
  1385. 'code' => TYPE_NOTAGS, # код активации из sms
  1386. 'step' => TYPE_NOTAGS, # этап
  1387. ), $p); extract($p, EXTR_REFS);
  1388.  
  1389. if (!$this->input->isPhoneNumber($phone)) {
  1390. $this->errors->set(_t('users', 'Номер телефона указан некорректно'), 'phone');
  1391. break;
  1392. }
  1393.  
  1394. if ($this->model->userPhoneExists($phone, $nUserID)) {
  1395. $this->errors->set(_t('users', 'Пользователь с таким номером телефона уже зарегистрирован'), 'phone');
  1396. break;
  1397. }
  1398.  
  1399. if ($step == 'code-send') {
  1400. $activationData = $this->getActivationInfo();
  1401.  
  1402. $res = $this->sms()->sendActivationCode($phone, $activationData['key']);
  1403. if ($res) {
  1404. $activationData = $this->updateActivationKey($nUserID, $activationData['key']);
  1405. if ( ! $activationData) {
  1406. $this->errors->reloadPage();
  1407. break;
  1408. }
  1409. }
  1410. } else if ($step == 'finish') {
  1411. $aUserData = $this->model->userData($nUserID, array('activate_key'));
  1412. if (empty($aUserData['activate_key'])) {
  1413. $this->errors->reloadPage(); break;
  1414. }
  1415. if (mb_strtolower($aUserData['activate_key']) !== mb_strtolower($code)) {
  1416. $this->errors->set(_t('users', 'Код подтверждения указан некорректно'), 'code');
  1417. break;
  1418. }
  1419. $res = $this->model->userSave($nUserID, array(
  1420. 'phone_number' => $phone,
  1421. 'phone_number_verified' => 1,
  1422. 'activate_key' => '',
  1423. ));
  1424. if (!empty($res)) {
  1425. $aResponse['phone'] = '+'.$phone;
  1426. } else {
  1427. $this->errors->reloadPage();
  1428. }
  1429. }
  1430.  
  1431. }
  1432. break;
  1433. case 'email': # смена email
  1434. {
  1435. if (!$on_email) {
  1436. $this->errors->reloadPage();
  1437. break;
  1438. }
  1439. $this->input->postm(array(
  1440. 'email' => array(TYPE_NOTAGS, 'len' => 100), # новый email
  1441. 'pass' => TYPE_NOTRIM, # текущий пароль
  1442. ), $p
  1443. );
  1444. extract($p, EXTR_REFS);
  1445.  
  1446. if (!User::isCurrentPassword($pass)) {
  1447. $this->errors->set(_t('users', 'Текущий пароль указан некорректно'), 'pass');
  1448. break;
  1449. }
  1450.  
  1451. if (!$this->input->isEmail($email)) {
  1452. $this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
  1453. break;
  1454. }
  1455.  
  1456. if ($this->model->userEmailExists($email)) {
  1457. $this->errors->set(_t('users', 'Пользователь с таким e-mail адресом уже зарегистрирован'), 'email');
  1458. break;
  1459. }
  1460.  
  1461. $res = $this->model->userSave($nUserID, array('email' => $email));
  1462. if (!empty($res)) {
  1463. $aResponse['email'] = $email;
  1464. $this->security->updateUserInfo(array('email' => $email));
  1465. } else {
  1466. $this->errors->reloadPage();
  1467. }
  1468.  
  1469. }
  1470. break;
  1471. case 'destroy': # удаление аккаунта
  1472. {
  1473. if (!$on_destroy) {
  1474. $this->errors->reloadPage();
  1475. break;
  1476. }
  1477. $pass = $this->input->post('pass', TYPE_NOTRIM);
  1478. if (!User::isCurrentPassword($pass)) {
  1479. $this->errors->set(_t('users', 'Текущий пароль указан некорректно'), 'pass');
  1480. break;
  1481. }
  1482.  
  1483. # TODO
  1484.  
  1485. $aResponse['redirect'] = bff::urlBase();
  1486.  
  1487. }
  1488. break;
  1489. default:
  1490. {
  1491. $this->errors->impossible();
  1492. }
  1493. break;
  1494. }
  1495.  
  1496. $this->ajaxResponseForm($aResponse);
  1497. }
  1498.  
  1499. $aData = $this->model->userData($nUserID, array(
  1500. 'user_id as id',
  1501. 'email',
  1502. 'phone_number',
  1503. 'phone_number_verified',
  1504. 'name',
  1505. 'enotify',
  1506. 'phones',
  1507. 'skype',
  1508. 'icq',
  1509. 'avatar',
  1510. 'sex',
  1511. 'addr_addr',
  1512. 'addr_lat',
  1513. 'addr_lon',
  1514. 'region_id'
  1515. ), true
  1516. );
  1517. if (empty($aData)) {
  1518. # ошибка получения данных о пользователе
  1519. bff::log('Неудалось получить данные о пользователе #' . $nUserID . ' [users::my_settings]');
  1520. $this->security->sessionDestroy();
  1521. }
  1522.  
  1523. $aData['avatar_normal'] = UsersAvatar::url($nUserID, $aData['avatar'], UsersAvatar::szNormal, $aData['sex']);
  1524. $aData['avatar_maxsize'] = $this->avatar($nUserID)->getMaxSize();
  1525.  
  1526. # координаты по-умолчанию
  1527. Geo::mapDefaultCoordsCorrect($aData['addr_lat'], $aData['addr_lon']);
  1528.  
  1529. # данные о привязанных соц. аккаунтах
  1530. $oSocial = $this->social();
  1531. $aSocialProviders = $oSocial->getProvidersEnabled();
  1532. $aSocialUser = $oSocial->getUserSocialAccountsData($nUserID);
  1533. foreach ($aSocialUser as $k => $v) {
  1534. if (isset($aSocialProviders[$k]) && strpos($v['profile_data'], 'a:') === 0) {
  1535. $aSocialProviders[$k]['user'] = func::unserialize($v['profile_data']);
  1536. }
  1537. }
  1538. $aData['social'] = $aSocialProviders;
  1539.  
  1540. # настройки уведомлений
  1541. $aData['enotify'] = $this->getEnotifyTypes($aData['enotify']);
  1542.  
  1543. # активный подраздел настроек
  1544. $tab = $this->input->getpost('t', TYPE_NOTAGS);
  1545. if (empty($tab)) {
  1546. if (!$on_contacts) {
  1547. $tab = 'shop';
  1548. } else {
  1549. if (!$nShopID || $nPublisher == BBS::PUBLISHER_USER) {
  1550. $tab = 'contacts';
  1551. }
  1552. }
  1553. }
  1554. $aData['tab'] = & $tab;
  1555.  
  1556. $aData['on'] = array(
  1557. 'contacts' => $on_contacts,
  1558. 'phone' => $on_phone,
  1559. 'email' => $on_email,
  1560. 'destroy' => $on_destroy,
  1561. );
  1562.  
  1563. return $this->viewPHP($aData, 'my.settings');
  1564. }
  1565.  
  1566. /**
  1567. * Меню пользователя (шапка, кабинет)
  1568. */
  1569. public function my_header_menu()
  1570. {
  1571. static $data;
  1572. if (isset($data)) {
  1573. return $data;
  1574. }
  1575.  
  1576. $data = array();
  1577.  
  1578. # данные о пользователе + счетчики
  1579. if (User::id()) {
  1580. $data['user'] = User::data(array('name', 'shop_id')) + User::counter(array());
  1581. } else {
  1582. $data['user'] = array('name' => _t('users', 'Гость'), 'shop_id' => 0);
  1583. }
  1584. # меню пользователя:
  1585. $data['menu'] = array();
  1586. $menu = & $data['menu'];
  1587.  
  1588. # > магазин
  1589. $shopID = User::shopID();
  1590. $shopsEnabled = bff::shopsEnabled();
  1591. $publisher = BBS::publisher();
  1592. if ($shopsEnabled && $shopID) {
  1593. $menu['shop'] = array(
  1594. 'i' => 'fa fa-shopping-cart',
  1595. 't' => _t('header', 'магазин'),
  1596. 'url' => Shops::url('my.shop')
  1597. );
  1598. }
  1599. # > объявления
  1600. $menu['items'] = array(
  1601. 't' => (
  1602. ($publisher == BBS::PUBLISHER_USER || !$data['user']['shop_id']) ?
  1603. _t('users', 'объявления') :
  1604. _t('users', 'частные объявления')
  1605. ),
  1606. 'i' => 'fa fa-list',
  1607. 'url' => BBS::url('my.items')
  1608. );
  1609. # скрываем раздел кабинета "объявления"
  1610. if ($shopsEnabled && $shopID) {
  1611. # при публикации только от "магазинов"
  1612. if ($publisher == BBS::PUBLISHER_SHOP) {
  1613. unset($menu['items']);
  1614. } else {
  1615. if ($publisher == BBS::PUBLISHER_USER_TO_SHOP) {
  1616. # после одобрения заявки магазина
  1617. if (Shops::model()->shopStatus($shopID) !== Shops::STATUS_REQUEST) {
  1618. unset($menu['items']);
  1619. }
  1620. }
  1621. }
  1622. }
  1623.  
  1624. # > избранные
  1625. $menu['favs'] = array('i' => 'fa fa-star', 't' => _t('users', 'избранные'), 'url' => BBS::url('my.favs'));
  1626.  
  1627. # > сообщения
  1628. $menu['messages'] = array(
  1629. 'i' => 'fa fa-comment',
  1630. 't' => _t('users', 'сообщения'),
  1631. 'url' => InternalMail::url('my.messages')
  1632. );
  1633.  
  1634. $menu[] = 'D'; // разделитель
  1635.  
  1636. # > счет
  1637. if (bff::servicesEnabled()) {
  1638. $menu['bill'] = array('i' => 'fa fa-retweet', 't' => _t('users', 'счет'), 'url' => Bills::url('my.history'));
  1639. }
  1640.  
  1641. # > настройки
  1642. $menu['settings'] = array(
  1643. 'i' => 'fa fa-pencil',
  1644. 't' => _t('users', 'настройки'),
  1645. 'url' => Users::url('my.settings')
  1646. );
  1647.  
  1648. $menu[] = 'D'; // разделитель
  1649.  
  1650. # > выход
  1651. $menu['logout'] = array('i' => 'fa fa-power-off', 't' => _t('users', 'выход'), 'url' => Users::url('logout'));
  1652.  
  1653. return $data;
  1654. }
  1655.  
  1656. # non-actions
  1657.  
  1658. protected function redirectToCabinet()
  1659. {
  1660. $this->redirect(static::url('my.settings'));
  1661. }
  1662.  
  1663. /**
  1664. * Форма отправки сообщения
  1665. * @param string $formID ID формы
  1666. * @return string HTML
  1667. */
  1668. public function writeForm($formID)
  1669. {
  1670. $aData = array('form_id' => $formID);
  1671.  
  1672. return $this->viewPHP($aData, 'write.form');
  1673. }
  1674.  
  1675. /**
  1676. * Обработчик формы отправки сообщения пользователю / магазину
  1677. * @param integer $authorID ID отправителя
  1678. * @param integer $receiverID ID получателя или 0 (владелец объявления)
  1679. * @param integer $itemID ID объявления или 0
  1680. * @param boolean $itemRequired ID объявления обязательно ($itemID != 0)
  1681. * @param integer|boolean $shopID ID магазина / 0 / -1 (ID магазина объявления)
  1682. */
  1683. public function writeFormSubmit($authorID, $receiverID, $itemID, $itemRequired, $shopID)
  1684. {
  1685. $aResponse = array();
  1686.  
  1687. do {
  1688. if (!$this->security->validateToken(true, false)) {
  1689. $this->errors->reloadPage();
  1690. break;
  1691. }
  1692. if (!$itemID && $itemRequired) {
  1693. $this->errors->reloadPage();
  1694. break;
  1695. }
  1696.  
  1697. if ($itemID) {
  1698. $itemData = BBS::model()->itemData($itemID, array(
  1699. 'id',
  1700. 'user_id',
  1701. 'shop_id',
  1702. 'link',
  1703. 'title',
  1704. 'status',
  1705. 'deleted'
  1706. )
  1707. );
  1708. if (empty($itemData) || $itemData['deleted'] || $itemData['status'] != BBS::STATUS_PUBLICATED) {
  1709. $this->errors->reloadPage();
  1710. break;
  1711. }
  1712. }
  1713.  
  1714. if (!$authorID) {
  1715. $email = $this->input->postget('email', TYPE_NOTAGS, array('len' => 150));
  1716. if (!$this->input->isEmail($email)) {
  1717. $this->errors->set(_t('', 'E-mail адрес указан некорректно'), 'email');
  1718. break;
  1719. }
  1720. }
  1721.  
  1722. $message = $this->input->post('message', TYPE_STR);
  1723. $message = $this->input->cleanTextPlain($message, 1000, false);
  1724. if (mb_strlen($message) < 10) {
  1725. $this->errors->set(_t('view', 'Сообщение слишком короткое'), 'message');
  1726. break;
  1727. }
  1728.  
  1729. if (!$authorID) {
  1730. $userData = Users::model()->userDataByFilter(array('email' => $email), array(
  1731. 'user_id',
  1732. 'blocked',
  1733. 'blocked_reason'
  1734. )
  1735. );
  1736. if (empty($userData)) {
  1737. # создаем новый аккаунт (неактивированный)
  1738. $userData = Users::i()->userRegister(array('email' => $email));
  1739. if (!empty($userData['user_id'])) {
  1740. $authorID = $userData['user_id'];
  1741. } else {
  1742. # ошибка регистрации
  1743. $this->errors->reloadPage();
  1744. break;
  1745. }
  1746. } else {
  1747. if ($userData['blocked']) {
  1748. $this->errors->set(_t('users', 'Данный аккаунт заблокирован по причине: [reason]',
  1749. array('reason' => $userData['blocked_reason'])
  1750. )
  1751. );
  1752. break;
  1753. }
  1754. $authorID = $userData['user_id'];
  1755. }
  1756. }
  1757.  
  1758. if ($itemID) {
  1759. $receiverID = $itemData['user_id'];
  1760. if ($shopID === -1) {
  1761. $shopID = $itemData['shop_id'];
  1762. }
  1763. }
  1764.  
  1765. # проверяем получателя
  1766. $receiver = $this->model->userData($receiverID, array('activated', 'blocked'));
  1767. if (empty($receiver) || $receiver['blocked'] || User::isCurrent($receiverID)) {
  1768. $this->errors->reloadPage();
  1769. break;
  1770. }
  1771.  
  1772. if ($authorID && $receiverID && ($authorID !== $receiverID)) {
  1773. # не чаще чем раз в {X} секунд с одного IP (для одного пользователя)
  1774. if (Site::i()->preventSpam('users-write-form', 5)) {
  1775. break;
  1776. }
  1777.  
  1778. # отправляем сообщение владельцу ОБ
  1779. $messageID = InternalMail::model()->sendMessage($authorID, $receiverID, $shopID, $message,
  1780. InternalMail::i()->attachUpload(),
  1781. $itemID
  1782. );
  1783. if ($messageID > 0 && $itemID) {
  1784. # обновляем счетчик сообщений ОБ
  1785. BBS::model()->itemSave($itemID, array(
  1786. 'messages_total = messages_total + 1',
  1787. 'messages_new = messages_new + 1',
  1788. )
  1789. );
  1790. }
  1791. }
  1792. } while (false);
  1793.  
  1794. $this->iframeResponseForm($aResponse);
  1795. }
  1796.  
  1797. public function ajax()
  1798. {
  1799. $response = array();
  1800. switch ($this->input->getpost('act', TYPE_STR)) {
  1801. case 'user-contacts': # просмотр контактов пользователя
  1802. {
  1803. $ex = $this->input->postget('ex', TYPE_STR);
  1804. if (empty($ex)) {
  1805. $this->errors->reloadPage();
  1806. break;
  1807. }
  1808. list($ex, $userID) = explode('-', $ex);
  1809.  
  1810. $user = $this->model->userData($userID, array(
  1811. 'user_id',
  1812. 'user_id_ex',
  1813. 'activated',
  1814. 'blocked',
  1815. 'phone_number',
  1816. 'phone_number_verified',
  1817. 'phones',
  1818. 'skype',
  1819. 'icq'
  1820. )
  1821. );
  1822.  
  1823. if (empty($user) || $user['user_id_ex'] != $ex || !$user['activated'] || $user['blocked'] ||
  1824. !$this->security->validateToken(true, false)
  1825. ) {
  1826. $this->errors->reloadPage();
  1827. break;
  1828. }
  1829.  
  1830. if (static::registerPhoneContacts() && $user['phone_number'] && $user['phone_number_verified']) {
  1831. if (empty($user['phones'])) $user['phones'] = array();
  1832. array_unshift($user['phones'], array('v'=>$user['phone_number']));
  1833. }
  1834.  
  1835. if (!empty($user['phones'])) {
  1836. if (!bff::deviceDetector(bff::DEVICE_PHONE)) {
  1837. $phones = array();
  1838. foreach ($user['phones'] as $v) $phones[] = $v['v'];
  1839. $response['phones'] = '<span><img src="' . Users::contactAsImage($phones) . '" /></span>';
  1840. } else {
  1841. $phones = '<span>'; $i = 1;
  1842. foreach ($user['phones'] as $v) {
  1843. $phone = HTML::obfuscate($v['v']);
  1844. $phones .= '<a href="tel:'.$phone.'">'.$phone.'</a>';
  1845. if ($i++ < sizeof($user['phones'])) {
  1846. $phones .= ', ';
  1847. }
  1848. }
  1849. $phones .= '</span>';
  1850. $response['phones'] = $phones;
  1851. }
  1852. }
  1853. if (!empty($user['skype'])) {
  1854. $skype = HTML::obfuscate($user['skype']);
  1855. $response['skype'] = '<a href="skype:' . $skype . '?call">' . $skype . '</a>';
  1856. }
  1857. if (!empty($user['icq'])) {
  1858. $response['icq'] = HTML::obfuscate($user['icq']);
  1859. }
  1860. }
  1861. break;
  1862. }
  1863.  
  1864. $this->ajaxResponseForm($response);
  1865. }
  1866.  
  1867. public function cron()
  1868. {
  1869. if (!bff::cron()) {
  1870. return;
  1871. }
  1872. $this->model->usersCronDeleteNotActivated();
  1873. }
  1874.  
  1875. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement