PageRenderTime 64ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/e107_handlers/user_model.php

https://github.com/CasperGemini/e107
PHP | 2598 lines | 1444 code | 316 blank | 838 comment | 230 complexity | d21b8b196be009bec2cd07c9344b6249 MD5 | raw file
Possible License(s): GPL-2.0

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

  1. <?php
  2. /*
  3. * e107 website system
  4. *
  5. * Copyright (C) 2008-2011 e107 Inc (e107.org)
  6. * Released under the terms and conditions of the
  7. * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
  8. *
  9. * User Model
  10. *
  11. * $URL$
  12. * $Id$
  13. */
  14. /**
  15. * @package e107
  16. * @subpackage e107_handlers
  17. * @version $Id$
  18. * @author SecretR
  19. *
  20. * Front-end User Models
  21. */
  22. if (!defined('e107_INIT'))
  23. {
  24. exit;
  25. }
  26. class e_user_model extends e_admin_model
  27. {
  28. /**
  29. * Describes all model data, used as _FIELD_TYPE array as well
  30. * @var array
  31. */
  32. protected $_data_fields = array(
  33. 'user_id' => 'integer',
  34. 'user_name' => 'string',
  35. 'user_loginname' => 'string',
  36. 'user_customtitle' => 'string',
  37. 'user_password' => 'string',
  38. 'user_sess' => 'string',
  39. 'user_email' => 'string',
  40. 'user_signature' => 'string',
  41. 'user_image' => 'string',
  42. 'user_hideemail' => 'integer',
  43. 'user_join' => 'integer',
  44. 'user_lastvisit' => 'integer',
  45. 'user_currentvisit' => 'integer',
  46. 'user_lastpost' => 'integer',
  47. 'user_chats' => 'integer',
  48. 'user_comments' => 'integer',
  49. 'user_ip' => 'string',
  50. 'user_ban' => 'integer',
  51. 'user_prefs' => 'string',
  52. 'user_visits' => 'integer',
  53. 'user_admin' => 'integer',
  54. 'user_login' => 'string',
  55. 'user_class' => 'string',
  56. 'user_perms' => 'string',
  57. 'user_realm' => 'string',
  58. 'user_pwchange' => 'integer',
  59. 'user_xup' => 'string',
  60. );
  61. /**
  62. * Validate required fields
  63. * @var array
  64. */
  65. protected $_validation_rules = array(
  66. 'user_name' => array('string', '1', 'LAN_USER_01', 'LAN_USER_HELP_01'), // TODO - regex
  67. 'user_loginname' => array('string', '1', 'LAN_USER_02', 'LAN_USER_HELP_02'), // TODO - regex
  68. 'user_password' => array('compare', '5', 'LAN_USER_05', 'LAN_USER_HELP_05'), // TODO - pref - modify it somewhere below - prepare_rules()?
  69. 'user_email' => array('email', '', 'LAN_USER_08', 'LAN_USER_HELP_08'),
  70. );
  71. /**
  72. * Validate optional fields - work in progress, not working yet
  73. * @var array
  74. */
  75. protected $_optional_rules = array(
  76. 'user_customtitle' => array('string', '1', 'LAN_USER_01'), // TODO - regex
  77. );
  78. /**
  79. * @see e_model
  80. * @var string
  81. */
  82. protected $_db_table = 'user';
  83. /**
  84. * @see e_model
  85. * @var string
  86. */
  87. protected $_field_id = 'user_id';
  88. /**
  89. * @see e_model
  90. * @var string
  91. */
  92. protected $_message_stack = 'user';
  93. /**
  94. * User class as set in user Adminsitration
  95. *
  96. * @var integer
  97. */
  98. protected $_memberlist_access = null;
  99. /**
  100. * Extended data
  101. *
  102. * @var e_user_extended_model
  103. */
  104. protected $_extended_model = null;
  105. /**
  106. * Extended structure
  107. *
  108. * @var e_user_extended_structure
  109. */
  110. protected $_extended_structure = null;
  111. /**
  112. * User preferences model
  113. * @var e_user_pref
  114. */
  115. protected $_user_config = null;
  116. /**
  117. * User model of current editor
  118. * @var e_user_model
  119. */
  120. protected $_editor = null;
  121. protected $_class_list;
  122. /**
  123. * Constructor
  124. * @param array $data
  125. * @return void
  126. */
  127. public function __construct($data = array())
  128. {
  129. $this->_memberlist_access = e107::getPref('memberlist_access');
  130. parent::__construct($data);
  131. }
  132. /**
  133. * Always return integer
  134. *
  135. * @see e107_handlers/e_model#getId()
  136. */
  137. public function getId()
  138. {
  139. return (integer) parent::getId();
  140. }
  141. /**
  142. * Try display name, fall back to login name when empty (shouldn't happen)
  143. */
  144. final public function getName($anon = false)
  145. {
  146. if($this->isUser())
  147. {
  148. return ($this->get('user_name') ? $this->get('user_name') : $this->get('user_loginname'));
  149. }
  150. return $anon;
  151. }
  152. /**
  153. * Display name getter. Use it as DB field name will be changed soon.
  154. */
  155. final public function getDisplayName()
  156. {
  157. return $this->get('user_name');
  158. }
  159. /**
  160. * Login name getter. Use it as DB field name will be changed soon.
  161. */
  162. final public function getLoginName()
  163. {
  164. return $this->get('user_loginname');
  165. }
  166. /**
  167. * Real name getter. Use it as DB field name will be changed soon.
  168. * @param bool $strict if false, fall back to Display name when empty
  169. */
  170. final public function getRealName($strict = false)
  171. {
  172. if($strict) return $this->get('user_login');
  173. return ($this->get('user_login') ? $this->get('user_login') : $this->get('user_name'));
  174. }
  175. final public function getAdminId()
  176. {
  177. return ($this->isAdmin() ? $this->getId() : false);
  178. }
  179. final public function getAdminName()
  180. {
  181. return ($this->isAdmin() ? $this->get('user_name') : false);
  182. }
  183. final public function getAdminEmail()
  184. {
  185. return ($this->isAdmin() ? $this->get('user_email') : false);
  186. }
  187. final public function getAdminPwchange()
  188. {
  189. return ($this->isAdmin() ? $this->get('user_pwchange') : false);
  190. }
  191. final public function getAdminPerms()
  192. {
  193. return ($this->isAdmin() ? $this->get('user_perms') : false);
  194. }
  195. /**
  196. * DEPRECATED - will be removed or changed soon (see e_session)
  197. * @return string
  198. */
  199. public function getToken()
  200. {
  201. if(null === $this->get('user_token'))
  202. {
  203. //$this->set('user_token', md5($this->get('user_password').$this->get('user_lastvisit').$this->get('user_pwchange').$this->get('user_class')));
  204. $this->set('user_token', e107::getSession()->getFormToken(false));
  205. }
  206. return $this->get('user_token');
  207. }
  208. public static function randomKey()
  209. {
  210. return md5(uniqid(rand(), 1));
  211. }
  212. public function isCurrent()
  213. {
  214. return false;
  215. }
  216. final public function isAdmin()
  217. {
  218. return ($this->get('user_admin') ? true : false);
  219. }
  220. final public function isMainAdmin()
  221. {
  222. return $this->checkAdminPerms('0');
  223. }
  224. final public function isUser()
  225. {
  226. return ($this->getId() ? true : false);
  227. }
  228. final public function isGuest()
  229. {
  230. return ($this->getId() ? false : true);
  231. }
  232. final public function hasBan()
  233. {
  234. return ((integer)$this->get('user_ban') === 1 ? true : false);
  235. }
  236. final public function hasRestriction()
  237. {
  238. return ((integer)$this->get('user_ban') === 0 ? false : true);
  239. }
  240. public function hasEditor()
  241. {
  242. return (null !== $this->_editor);
  243. }
  244. final protected function _setClassList()
  245. {
  246. $this->_class_list = array();
  247. if ($this->isUser())
  248. {
  249. if ($this->get('user_class'))
  250. {
  251. // list of all 'inherited' user classes, convert elements to integer
  252. $this->_class_list = array_map('intval', e107::getUserClass()->get_all_user_classes($this->get('user_class'), true));
  253. }
  254. $this->_class_list[] = e_UC_MEMBER;
  255. if ($this->isAdmin())
  256. {
  257. $this->_class_list[] = e_UC_ADMIN;
  258. }
  259. if ($this->isMainAdmin())
  260. {
  261. $this->_class_list[] = e_UC_MAINADMIN;
  262. }
  263. }
  264. else
  265. {
  266. $this->_class_list[] = e_UC_GUEST;
  267. }
  268. $this->_class_list[] = e_UC_READONLY;
  269. $this->_class_list[] = e_UC_PUBLIC;
  270. // unique, rebuild indexes
  271. $this->_class_list = array_merge(array_unique($this->_class_list));
  272. return $this;
  273. }
  274. final public function getClassList($toString = false)
  275. {
  276. if (null === $this->_class_list)
  277. {
  278. $this->_setClassList();
  279. }
  280. return ($toString ? implode(',', $this->_class_list) : $this->_class_list);
  281. }
  282. final public function getClassRegex()
  283. {
  284. return '(^|,)('.str_replace(',', '|', $this->getClassList(true)).')(,|$)';
  285. }
  286. final public function checkClass($class, $allowMain = true)
  287. {
  288. // FIXME - replace check_class() here
  289. return (($allowMain && $this->isMainAdmin()) || check_class($class, $this->getClassList(), 0));
  290. }
  291. final public function checkAdminPerms($perm_str)
  292. {
  293. // FIXME - method to replace getperms()
  294. return ($this->isAdmin() && getperms($perm_str, $this->getAdminPerms()));
  295. }
  296. final public function checkEditorPerms($class = '')
  297. {
  298. if (!$this->hasEditor())
  299. return false;
  300. $editor = $this->getEditor();
  301. if ('' !== $class)
  302. return ($editor->isAdmin() && $editor->checkClass($class));
  303. return $editor->isAdmin();
  304. }
  305. /**
  306. * Check passed value against current user token
  307. * DEPRECATED - will be removed or changed soon (see e_core_session)
  308. * @param string $token md5 sum of e.g. posted token
  309. * @return boolean
  310. */
  311. final public function checkToken($token)
  312. {
  313. $utoken = $this->getToken();
  314. return (null !== $utoken && $token === md5($utoken));
  315. }
  316. /**
  317. * Bad but required (BC) method of retrieving all user data
  318. * It's here to be used from get_user_data() core function.
  319. * DON'T USE THEM BOTH unless you have VERY good reason to do it.
  320. *
  321. * @return array
  322. */
  323. public function getUserData()
  324. {
  325. // revised - don't call extended object, no permission checks, just return joined user data
  326. $ret = $this->getData();
  327. // $ret = array_merge($this->getExtendedModel()->getExtendedData(), $this->getData());
  328. if ($ret['user_perms'] == '0.') $ret['user_perms'] = '0';
  329. $ret['user_baseclasslist'] = $ret['user_class'];
  330. $ret['user_class'] = $this->getClassList(true);
  331. return $ret;
  332. }
  333. /**
  334. * Check if given field name is present in core user table structure
  335. *
  336. * @param string $field
  337. * @param boolean $short
  338. * @return boolean
  339. */
  340. public function isCoreField($field, $short = true)
  341. {
  342. if($short) $field = 'user_'.$field;
  343. return isset($this->_data_fields[$field]);
  344. }
  345. /**
  346. * Check if given field name is present in extended user table structure
  347. *
  348. * @param string $field
  349. * @param boolean $short
  350. * @return boolean
  351. */
  352. public function isExtendedField($field, $short = true)
  353. {
  354. if($short) $field = 'user_'.$field;
  355. if($this->isCoreField($field, false))
  356. {
  357. return false;
  358. }
  359. return $this->getExtendedModel()->isField($field, false);
  360. }
  361. /**
  362. * Get User value from core user table.
  363. * This method doesn't perform any read permission cheks.
  364. *
  365. * @param string $field
  366. * @param mixed $default
  367. * @param boolean $short if true, 'user_' prefix will be added to field name
  368. * @return mixed if field is not part of core user table returns null by default
  369. */
  370. public function getCore($field, $default = null, $short = true)
  371. {
  372. if($short) $field = 'user_'.$field;
  373. if($this->isCoreField($field, false)) return $this->get($field, $default);
  374. return $default;
  375. }
  376. /**
  377. * Set User value (core user field).
  378. * This method doesn't perform any write permission cheks.
  379. *
  380. * @param string $field
  381. * @param mixed $value
  382. * @param boolean $short if true, 'user_' prefix will be added to field name
  383. * @param boolean $strict if false no Applicable check will be made
  384. * @return e_user_model
  385. */
  386. public function setCore($field, $value, $short = true, $strict = false)
  387. {
  388. if($short) $field = 'user_'.$field;
  389. if($this->isCoreField($field, false)) $this->set($field, $value, $strict);
  390. return $this;
  391. }
  392. /**
  393. * Get User extended value.
  394. * This method doesn't perform any read permission cheks.
  395. *
  396. * @param string $field
  397. * @param boolean $short if true, 'user_' prefix will be added to field name
  398. * @param boolean $raw get raw DB values (no SQL query)
  399. * @return mixed
  400. */
  401. public function getExtended($field, $short = true, $raw = true)
  402. {
  403. return $this->getExtendedModel()->getSystem($field, $short, $raw);
  404. }
  405. /**
  406. * Set User extended value.
  407. * This method doesn't perform any write permission cheks.
  408. *
  409. * @param string $field
  410. * @param mixed $value
  411. * @param boolean $short if true, 'user_' prefix will be added to field name
  412. * @param boolean $strict if false no Applicable check will be made
  413. * @return e_user_model
  414. */
  415. public function setExtended($field, $value, $short = true, $strict = false)
  416. {
  417. $this->getExtendedModel()->setSystem($field, $value, $short, $strict);
  418. return $this;
  419. }
  420. /**
  421. * Get User extended value after checking read permissions against current Editor
  422. *
  423. * @param string $field
  424. * @param boolean $short if true, 'user_' prefix will be added to field name
  425. * @param boolean $raw get raw DB values (no SQL query)
  426. * @return mixed
  427. */
  428. public function getExtendedFront($field, $short = true, $raw = false)
  429. {
  430. return $this->getExtendedModel()->getValue($field, $short, $raw);
  431. }
  432. /**
  433. * Set User extended value after checking write permissions against current Editor.
  434. *
  435. * @param string $field
  436. * @param mixed $value
  437. * @param boolean $short if true, 'user_' prefix will be added to field name
  438. * @return e_user_model
  439. */
  440. public function setExtendedFront($field, $value, $short = true)
  441. {
  442. $this->getExtendedModel()->setValue($field, $value, $short);
  443. return $this;
  444. }
  445. /**
  446. * Transparent front-end getter. It performs all required read/applicable permission checks
  447. * against current editor/user. It doesn't distinguish core and extended fields.
  448. * It grants BC.
  449. * It's what you'd need in all front-end parsing code (e.g. shortcodes)
  450. *
  451. * @param string $field
  452. * @param mixed $default
  453. * @param boolean $short if true, 'user_' prefix will be added to field name
  454. * @param boolean $rawExtended get raw DB values (no SQL query) - used only for extended fields
  455. * @return mixed if field is not readable returns null by default
  456. */
  457. public function getValue($field, $default = null, $short = true, $rawExtended = false)
  458. {
  459. if($short)
  460. {
  461. $mfield = $field;
  462. $field = 'user_'.$field;
  463. }
  464. else
  465. {
  466. $mfield = substr($field, 5);
  467. }
  468. // check for BC/override method first e.g. getSingatureValue($default, $system = false, $rawExtended);
  469. $method = 'get'.ucfirst($mfield).'Value';
  470. if(method_exists($this, $method)) return $this->$method($default, false, $rawExtended);
  471. if($this->isCoreField($field, false))
  472. {
  473. if(!$this->isReadable($field)) return $default;
  474. return $this->getCore($field, $default, false);
  475. }
  476. return $this->getExtendedFront($field, false, $rawExtended);
  477. }
  478. /**
  479. * Transparent front-end setter. It performs all required write/applicable permission checks
  480. * against current editor/user. It doesn't distinguish core and extended fields.
  481. * It grants BC.
  482. * It's what you'd need on all user front-end manipulation events (e.g. user settings page related code)
  483. * NOTE: untrusted data should be provided via setPosted() method!
  484. *
  485. * @param string $field
  486. * @param mixed $value
  487. * @param boolean $short if true, 'user_' prefix will be added to field name
  488. * @return e_user_model
  489. */
  490. public function setValue($field, $value, $short = true)
  491. {
  492. if($short)
  493. {
  494. $mfield = $field;
  495. $field = 'user_'.$field;
  496. }
  497. else
  498. {
  499. $mfield = substr($field, 5);
  500. }
  501. // check for BC/override method first e.g. setSingatureValue($value, $system = false);
  502. $method = 'set'.ucfirst($mfield).'Value';
  503. if(method_exists($this, $method))
  504. {
  505. $this->$method($value, false);
  506. return $this;
  507. }
  508. if($this->isCoreField($field, false))
  509. {
  510. if($this->isWritable($field)) $this->setCore($field, $value, false, true);
  511. }
  512. else
  513. {
  514. $this->setExtendedFront($field, $value, false);
  515. }
  516. return $this;
  517. }
  518. /**
  519. * Transparent system getter. It doesn't perform any read/applicable permission checks
  520. * against current editor/user. It doesn't distinguish core and extended fields.
  521. * It grants BC.
  522. * It's here to serve in your application logic.
  523. *
  524. * @param string $field
  525. * @param mixed $default
  526. * @param boolean $short if true, 'user_' prefix will be added to field name
  527. * @param boolean $rawExtended get raw DB values (no SQL query) - used only for extended fields
  528. * @return mixed
  529. */
  530. public function getSystem($field, $default = null, $short = true, $rawExtended = true)
  531. {
  532. if($short)
  533. {
  534. $mfield = $field;
  535. $field = 'user_'.$field;
  536. }
  537. else
  538. {
  539. $mfield = substr($field, 5);
  540. }
  541. // check for BC/override method first e.g. getSingatureValue($default, $system = true, $rawExtended);
  542. $method = 'get'.ucfirst($mfield).'Value';
  543. if(method_exists($this, $method)) return $this->$method($default, true, $rawExtended);
  544. if($this->isCoreField($field, false))
  545. {
  546. return $this->getCore($field, $default, false);
  547. }
  548. return $this->getExtended($field, false, $rawExtended);
  549. }
  550. /**
  551. * Transparent front-end setter. It doesn't perform any write/applicable permission checks
  552. * against current editor/user. It doesn't distinguish core and extended fields.
  553. * It's here to serve in your application logic.
  554. * NOTE: untrusted data should be provided via setPosted() method!
  555. *
  556. * @param string $field
  557. * @param mixed $value
  558. * @param boolean $short if true, 'user_' prefix will be added to field name
  559. * @param boolean $strict if false no Applicable check will be made
  560. * @return e_user_model
  561. */
  562. public function setSystem($field, $value, $short = true, $strict = false)
  563. {
  564. if($short)
  565. {
  566. $mfield = $field;
  567. $field = 'user_'.$field;
  568. }
  569. else
  570. {
  571. $mfield = substr($field, 5);
  572. }
  573. // check for BC/override method first e.g. setSingatureValue($value, $system = true);
  574. $method = 'set'.ucfirst($mfield).'Value';
  575. if(method_exists($this, $method))
  576. {
  577. $this->$method($value, true);
  578. return $this;
  579. }
  580. if($this->isCoreField($field, false))
  581. {
  582. $this->setCore($field, $value, false, $strict);
  583. }
  584. else
  585. {
  586. $this->setExtended($field, $value, false, $strict);
  587. }
  588. return $this;
  589. }
  590. /**
  591. * Just an example override method. This method is auto-magically called by getValue/System
  592. * getters.
  593. * $rawExtended is not used (here for example purposes only)
  594. * If user_signature become extended field one day, we'd need this method
  595. * for real - it'll call extended getters to retrieve the required value.
  596. *
  597. * @param mixed $default optional
  598. * @param boolean $system optional
  599. * @param boolean $rawExtended optional
  600. * @return mixed value
  601. */
  602. public function getSignatureValue($default = null, $system = false, $rawExtended = true)
  603. {
  604. if($system || $this->isReadable('user_signature')) return $this->getCore('signature', $default);
  605. return $default;
  606. }
  607. /**
  608. * Just an example override method. This method is auto-magically called by setValue/System
  609. * setters.
  610. * If user_signature become extended field one day, we'd need this method
  611. * for real - it'll call extended setters to set the new signature value
  612. *
  613. * @param string $value
  614. * @param boolean $system
  615. * @return e_user_model
  616. */
  617. public function setSignatureValue($value, $system = false)
  618. {
  619. if($system || $this->isWritable('user_signature')) $this->setCore('signature', $value);
  620. return $this;
  621. }
  622. /**
  623. * Get user preference
  624. * @param string $pref_name
  625. * @param mixed $default
  626. * @return mixed
  627. */
  628. public function getPref($pref_name = null, $default = null)
  629. {
  630. if(null === $pref_name) return $this->getConfig()->getData();
  631. return $this->getConfig()->get($pref_name, $default);
  632. }
  633. /**
  634. * Set user preference
  635. * @param string $pref_name
  636. * @param mixed $value
  637. * @return e_user_model
  638. */
  639. public function setPref($pref_name, $value = null)
  640. {
  641. $this->getConfig()->set($pref_name, $value);
  642. return $this;
  643. }
  644. /**
  645. * Get user preference (advanced - slower)
  646. * @param string $pref_path
  647. * @param mixed $default
  648. * @param integer $index if number, value will be exploded by "\n" and corresponding index will be returned
  649. * @return mixed
  650. */
  651. public function findPref($pref_path = null, $default = null, $index = null)
  652. {
  653. return $this->getConfig()->getData($pref_path, $default, $index);
  654. }
  655. /**
  656. * Set user preference (advanced - slower)
  657. * @param string $pref_path
  658. * @param mixed $value
  659. * @return e_user_model
  660. */
  661. public function setPrefData($pref_path, $value = null)
  662. {
  663. $this->getConfig()->setData($pref_path, $value = null);
  664. return $this;
  665. }
  666. /**
  667. * New - External login providers support
  668. * @return string Provider name
  669. */
  670. public function getProviderName()
  671. {
  672. if($this->get('user_xup'))
  673. {
  674. return array_shift(explode('_', $this->get('user_xup')));
  675. }
  676. return null;
  677. }
  678. /**
  679. * New - External login providers support
  680. * @return boolean Check if there is external provider data
  681. */
  682. public function hasProviderName()
  683. {
  684. return $this->has('user_xup');
  685. }
  686. /**
  687. * Get user extended model
  688. *
  689. * @return e_user_extended_model
  690. */
  691. public function getExtendedModel()
  692. {
  693. if (null === $this->_extended_model)
  694. {
  695. $this->_extended_model = new e_user_extended_model($this);
  696. }
  697. return $this->_extended_model;
  698. }
  699. /**
  700. * Set user extended model
  701. *
  702. * @param e_user_extended_model $extended_model
  703. * @return e_user_model
  704. */
  705. public function setExtendedModel($extended_model)
  706. {
  707. $this->_extended_model = $extended_model;
  708. return $this;
  709. }
  710. /**
  711. * Get user config model
  712. *
  713. * @return e_user_pref
  714. */
  715. public function getConfig()
  716. {
  717. if (null === $this->_user_config)
  718. {
  719. $this->_user_config = new e_user_pref($this);
  720. }
  721. return $this->_user_config;
  722. }
  723. /**
  724. * Set user config model
  725. *
  726. * @param e_user_pref $user_config
  727. * @return e_user_model
  728. */
  729. public function setConfig(e_user_pref $user_config)
  730. {
  731. $this->_user_config = $user_config;
  732. return $this;
  733. }
  734. /**
  735. * Get current user editor model
  736. * @return e_user_model
  737. */
  738. public function getEditor()
  739. {
  740. return $this->_editor;
  741. }
  742. /**
  743. * Set current user editor model
  744. * @return e_user_model
  745. */
  746. public function setEditor(e_user_model $user_model)
  747. {
  748. $this->_editor = $user_model;
  749. return $this;
  750. }
  751. /**
  752. * Check if passed field is writable
  753. * @param string $field
  754. * @return boolean
  755. */
  756. public function isWritable($field)
  757. {
  758. $perm = false;
  759. $editor = $this->getEditor();
  760. if($this->getId() === $editor->getId() || $editor->isMainAdmin() || $editor->checkAdminPerms('4'))
  761. $perm = true;
  762. return ($perm && !in_array($field, array($this->getFieldIdName(), 'user_admin', 'user_perms', 'user_prefs')));
  763. }
  764. /**
  765. * Check if passed field is readable by the Editor
  766. * @param string $field
  767. * @return boolean
  768. */
  769. public function isReadable($field)
  770. {
  771. $perm = false;
  772. $editor = $this->getEditor();
  773. if($this->getId() === $editor->getId() || $editor->isMainAdmin() || $editor->checkAdminPerms('4'))
  774. $perm = true;
  775. return ($perm || (!in_array($field, array('user_admin', 'user_perms', 'user_prefs', 'user_password') && $editor->checkClass($this->_memberlist_access))));
  776. }
  777. /**
  778. * Set current object as a target
  779. *
  780. * @return e_user_model
  781. */
  782. protected function setAsTarget()
  783. {
  784. e107::setRegistry('core/e107/user/'.$this->getId(), $this);
  785. return $this;
  786. }
  787. /**
  788. * Clear registered target
  789. *
  790. * @return e_user_model
  791. */
  792. protected function clearTarget()
  793. {
  794. e107::setRegistry('core/e107/user'.$this->getId(), null);
  795. return $this;
  796. }
  797. /**
  798. * @see e_model#load($id, $force)
  799. */
  800. public function load($user_id = 0, $force = false)
  801. {
  802. $qry = "SELECT u.*, ue.* FROM #user AS u LEFT JOIN #user_extended as ue ON u.user_id=ue.user_extended_id WHERE user_id={ID}";
  803. $this->setParam('db_query', $qry);
  804. parent::load($user_id, $force);
  805. if ($this->getId())
  806. {
  807. // no errors - register
  808. $this->setAsTarget()
  809. ->setEditor(e107::getUser()); //set current user as default editor
  810. }
  811. }
  812. /**
  813. * Additional security while applying posted
  814. * data to user model
  815. * @return e_user_model
  816. */
  817. public function mergePostedData()
  818. {
  819. $posted = $this->getPostedData();
  820. foreach ($posted as $key => $value)
  821. {
  822. if(!$this->isWritable($key))
  823. {
  824. $this->removePosted($key);
  825. continue;
  826. }
  827. $this->_modifyPostedData($key, $value);
  828. }
  829. parent::mergePostedData(true, true, true);
  830. return $this;
  831. }
  832. protected function _modifyPostedData($key, $value)
  833. {
  834. // TODO - add more here
  835. switch ($key)
  836. {
  837. case 'password1':
  838. // compare validation rule
  839. $this->setPosted('user_password', array($value, $this->getPosted('password2')));
  840. break;
  841. }
  842. }
  843. /**
  844. * Send model data to DB
  845. */
  846. public function save($noEditorCheck = false, $force = false, $session = false)
  847. {
  848. if (!$noEditorCheck && !$this->checkEditorPerms())
  849. {
  850. return false; // TODO - message, admin log
  851. }
  852. // sync user prefs
  853. $this->getConfig()->apply();
  854. // TODO - do the save manually in this order: validate() on user model, save() on extended fields, save() on user model
  855. $ret = parent::save(true, $force, $session);
  856. if(false !== $ret && null !== $this->_extended_model) // don't load extended fields if not already used
  857. {
  858. $ret_e = $this->_extended_model->save($force, $session);
  859. if(false !== $ret_e)
  860. {
  861. return ($ret_e + $ret);
  862. }
  863. return false;
  864. }
  865. return $ret;
  866. }
  867. public function saveDebug($extended = true, $return = false, $undo = true)
  868. {
  869. $ret = array();
  870. $ret['CORE_FIELDS'] = parent::saveDebug(true, $undo);
  871. if($extended && null !== $this->_extended_model)
  872. {
  873. $ret['EXTENDED_FIELDS'] = $this->_extended_model->saveDebug(true, $undo);
  874. }
  875. if($return) return $ret;
  876. print_a($ret);
  877. }
  878. public function destroy()
  879. {
  880. $this->clearTarget()
  881. ->removeData();
  882. $this->_class_list = array();
  883. $this->_editor = null;
  884. $this->_extended_structure = null;
  885. $this->_user_config = null;
  886. if (null !== $this->_extended_model)
  887. {
  888. $this->_extended_model->destroy();
  889. $this->_extended_model = null;
  890. }
  891. }
  892. }
  893. // TODO - add some more useful methods, sc_* methods support
  894. class e_system_user extends e_user_model
  895. {
  896. /**
  897. * Constructor
  898. *
  899. * @param array $user_data trusted data, loaded from DB
  900. * @return void
  901. */
  902. public function __construct($user_data = array())
  903. {
  904. parent::__construct($user_data);
  905. $this->setEditor(e107::getUser());
  906. }
  907. /**
  908. * Returns always false
  909. * Even if user data belongs to the current user, Current User interface
  910. * is not available
  911. *
  912. * @return boolean
  913. */
  914. final public function isCurrent()
  915. {
  916. // check against current system user
  917. //return ($this->getId() && $this->getId() == e107::getUser()->getId());
  918. return false;
  919. }
  920. /**
  921. * Send user email
  922. * @param mixed $userInfo array data or null for current logged in user or any object subclass of e_object (@see e_system_user::renderEmail() for field requirements)
  923. */
  924. public function email($type = 'email', $options = array(), $userInfo = null)
  925. {
  926. if(null === $userInfo)
  927. {
  928. $userInfo = $this->getData();
  929. }
  930. elseif(is_object($userInfo) && get_class($userInfo) == 'e_object' || is_subclass_of($userInfo, 'e_object'))
  931. {
  932. $userInfo = $userInfo->getData();
  933. }
  934. if(empty($userInfo) || !vartrue($userInfo['user_email'])) return false;
  935. // plain password could be passed only via $options
  936. unset($userInfo['user_password']);
  937. if($options && is_array($options))
  938. {
  939. $userInfo = array_merge($options, $userInfo);
  940. }
  941. $eml = $this->renderEmail($type, $userInfo);
  942. if(empty($eml)) return false;
  943. $mailer = e107::getEmail();
  944. $mailer->template = $eml['template'];
  945. unset($eml['template']);
  946. // Custom e107 Header
  947. if($userInfo['user_id'])
  948. {
  949. $mailer->AddCustomHeader("X-e107-id: {$userInfo['user_id']}");
  950. }
  951. return $mailer->sendEmail($userInfo['user_email'], $userInfo['user_name'], $eml, false);
  952. }
  953. /**
  954. * Render user email.
  955. * Additional user fields:
  956. * 'mail_subject' -> required when type is not signup
  957. * 'mail_body' -> required when type is not signup
  958. * 'mail_copy_to' -> optional, carbon copy, used when type is not signup
  959. * 'mail_bcopy_to' -> optional, blind carbon copy, used when type is not signup
  960. * 'mail_attach' -> optional, attach files, available for all types, additionally it overrides $SIGNUPEMAIL_ATTACHMENTS when type is signup
  961. * 'mail_options' -> optional, available for all types, any additional valid mailer option as described in e107Email::sendEmail() phpDoc help (options above can override them)
  962. * All standard user fields from the DB (user_name, user_loginname, etc.)
  963. *
  964. * @param string $type signup|notify|email|quickadd
  965. * @param array $userInfo
  966. * @return array
  967. */
  968. public function renderEmail($type, $userInfo)
  969. {
  970. $pref = e107::getPref();
  971. $ret = array();
  972. // mailer options
  973. if(isset($userInfo['mail_options']) && is_array($userInfo['mail_options']))
  974. {
  975. $ret = $userInfo['mail_options'];
  976. }
  977. // required for signup and quickadd email type
  978. e107::coreLan('signup');
  979. // FIXME convert to the new template to avoid include on every call
  980. // BC
  981. if (file_exists(THEME.'email_template.php'))
  982. {
  983. include(THEME.'email_template.php');
  984. }
  985. else
  986. {
  987. // new standards
  988. include(e107::coreTemplatePath('email'));
  989. }
  990. // FIXME by SecretR - email template mess - there are changes to emails and templates that need to be implemented here
  991. $template = '';
  992. switch ($type)
  993. {
  994. case 'signup':
  995. if(vartrue($SIGNUPPROVIDEREMAIL_TEMPLATE)) $template = $SIGNUPPROVIDEREMAIL_TEMPLATE;
  996. else $template = $SIGNUPEMAIL_TEMPLATE;
  997. $ret['template'] = false; // Don't allow additional headers (mailer)
  998. break;
  999. case 'quickadd':
  1000. $template = $QUICKADDUSER_TEMPLATE['email_body']; // XXX quick fix - add the email templating engine
  1001. $ret['template'] = 'email'; // Don't allow additional headers (mailer)
  1002. break;
  1003. case 'notify': //emailer changes
  1004. if(vartrue($userInfo['mail_body'])) $template = $userInfo['mail_body'];//$NOTIFY_HEADER.$userInfo['mail_body'].$NOTIFY_FOOTER;
  1005. $ret['template'] = 'notify';
  1006. break;
  1007. case 'email'://emailer changes
  1008. if(vartrue($userInfo['mail_body'])) $template = $userInfo['mail_body']; //$EMAIL_HEADER.$userInfo['mail_body'].$EMAIL_FOOTER;
  1009. $ret['template'] = 'email';
  1010. break;
  1011. }
  1012. if(!$template) return array();
  1013. $pass_show = varset($userInfo['user_password']);
  1014. // signup email only
  1015. if($type == 'signup')
  1016. {
  1017. $ret['e107_header'] = $userInfo['user_id'];
  1018. if (vartrue($SIGNUPEMAIL_CC)) { $ret['email_copy_to'] = $SIGNUPEMAIL_CC; }
  1019. if (vartrue($SIGNUPEMAIL_BCC)) { $ret['email_bcopy_to'] = $SIGNUPEMAIL_BCC; }
  1020. if (vartrue($userInfo['email_attach'])) { $ret['email_attach'] = $userInfo['mail_attach']; }
  1021. elseif (vartrue($SIGNUPEMAIL_ATTACHMENTS)) { $ret['email_attach'] = $SIGNUPEMAIL_ATTACHMENTS; }
  1022. $style = vartrue($SIGNUPEMAIL_LINKSTYLE) ? "style='{$SIGNUPEMAIL_LINKSTYLE}'" : "";
  1023. $search[0] = '{LOGINNAME}';
  1024. $replace[0] = intval($pref['allowEmailLogin']) === 0 ? $userInfo['user_loginname'] : $userInfo['user_email'];
  1025. $search[1] = '{PASSWORD}';
  1026. $replace[1] = $pass_show ? $pass_show : '******';
  1027. $search[2] = '{ACTIVATION_LINK}';
  1028. $replace[2] = strpos($userInfo['activation_url'], 'http') === 0 ? '<a href="'.$userInfo['activation_url'].'">'.$userInfo['activation_url'].'</a>' : $userInfo['activation_url'];
  1029. $search[3] = '{SITENAME}';
  1030. $replace[3] = SITENAME;
  1031. $search[4] = '{SITEURL}';
  1032. $replace[4] = "<a href='".SITEURL."' {$style}>".SITEURL."</a>";
  1033. $search[5] = '{USERNAME}';
  1034. $replace[5] = $userInfo['user_name'];
  1035. $search[6] = '{USERURL}';
  1036. $replace[6] = varsettrue($userInfo['user_website']) ? $userInfo['user_website'] : "";
  1037. $search[7] = '{DISPLAYNAME}';
  1038. $replace[7] = $userInfo['user_login'] ? $userInfo['user_login'] : $userInfo['user_name'];
  1039. $search[8] = '{EMAIL}';
  1040. $replace[8] = $userInfo['user_email'];
  1041. $search[9] = '{ACTIVATION_URL}';
  1042. $replace[9] = $userInfo['activation_url'];
  1043. $subject = str_replace($search, $replace, $SIGNUPEMAIL_SUBJECT);
  1044. $ret['email_subject'] = $subject;
  1045. $ret['send_html'] = TRUE;
  1046. $HEAD = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n";
  1047. $HEAD .= "<html xmlns='http://www.w3.org/1999/xhtml' >\n";
  1048. $HEAD .= "<head><meta http-equiv='content-type' content='text/html; charset=utf-8' />\n";
  1049. $HEAD .= ($SIGNUPEMAIL_USETHEME == 1) ? "<link rel=\"stylesheet\" href=\"".SITEURLBASE.THEME_ABS."style.css\" type=\"text/css\" />\n" : "";
  1050. $HEAD .= "<title>".LAN_SIGNUP_58."</title>\n";
  1051. if($SIGNUPEMAIL_USETHEME == 2)
  1052. {
  1053. $CSS = file_get_contents(THEME."style.css");
  1054. $HEAD .= "<style>\n".$CSS."\n</style>";
  1055. }
  1056. $HEAD .= "</head>\n";
  1057. if(vartrue($SIGNUPEMAIL_BACKGROUNDIMAGE))
  1058. {
  1059. $HEAD .= "<body background=\"".$SIGNUPEMAIL_BACKGROUNDIMAGE."\" >\n";
  1060. }
  1061. else
  1062. {
  1063. $HEAD .= "<body>\n";
  1064. }
  1065. $FOOT = "\n</body>\n</html>\n";
  1066. $ret['send_html'] = TRUE;
  1067. $ret['email_body'] = e107::getParser()->parseTemplate(str_replace($search,$replace,$HEAD.$template.$FOOT), true);
  1068. $ret['preview'] = $ret['email_body'];// Non-standard field
  1069. return $ret;
  1070. }
  1071. // all other email types
  1072. $subject = $userInfo['email_subject'];
  1073. if(!$subject) return array();
  1074. $ret['e107_header'] = $userInfo['user_id'];
  1075. if (vartrue($userInfo['email_copy_to'])) { $ret['email_copy_to'] = $userInfo['email_copy_to']; }
  1076. if (vartrue($userInfo['email_bcopy_to'])) { $ret['email_bcopy_to'] = $userInfo['email_bcopy_to']; }
  1077. if (vartrue($userInfo['email_attach'])) { $ret['email_attach'] = $userInfo['email_attach']; }
  1078. $search[0] = '{LOGINNAME}';
  1079. $replace[0] = intval($pref['allowEmailLogin']) === 0 ? $userInfo['user_loginname'] : $userInfo['user_email'];
  1080. $search[1] = '{DISPLAYNAME}';
  1081. $replace[1] = $userInfo['user_login'] ? $userInfo['user_login'] : $userInfo['user_name'];
  1082. $search[2] = '{EMAIL}';
  1083. $replace[2] = $userInfo['user_email'];
  1084. $search[3] = '{SITENAME}';
  1085. $replace[3] = SITENAME;
  1086. $search[4] = '{SITEURL}';
  1087. $replace[4] = "<a href='".SITEURL."'>".SITEURL."</a>";
  1088. $search[5] = '{USERNAME}';
  1089. $replace[5] = $userInfo['user_name'];
  1090. $search[6] = '{USERURL}';
  1091. $replace[6] = vartrue($userInfo['user_website']) ? $userInfo['user_website'] : "";
  1092. $ret['email_subject'] = str_replace($search, $replace, $subject);
  1093. $search[7] = '{PASSWORD}';
  1094. $replace[7] = $pass_show ? $pass_show : '******';
  1095. if(isset($userInfo['activation_url']))
  1096. {
  1097. $search[8] = '{ACTIVATION_URL}';
  1098. $replace[8] = $userInfo['activation_url'];
  1099. $search[9] = '{ACTIVATION_LINK}';
  1100. $replace[9] = strpos($userInfo['activation_url'], 'http') === 0 ? '<a href="'.$userInfo['activation_url'].'">'.$userInfo['activation_url'].'</a>' : $userInfo['activation_url'];
  1101. }
  1102. $ret['send_html'] = TRUE;
  1103. $ret['email_body'] = e107::getParser()->parseTemplate(str_replace($search, $replace, $template));
  1104. $ret['preview'] = $ret['mail_body']; // Non-standard field
  1105. return $ret;
  1106. }
  1107. }
  1108. /**
  1109. * Current system user
  1110. * @author SecretR
  1111. */
  1112. class e_user extends e_user_model
  1113. {
  1114. private $_session_data = null;
  1115. private $_session_key = null;
  1116. private $_session_type = null;
  1117. private $_session_error = false;
  1118. private $_parent_id = false;
  1119. private $_parent_data = array();
  1120. private $_parent_extmodel = null;
  1121. private $_parent_extstruct = null;
  1122. private $_parent_config = null;
  1123. /**
  1124. * @var Hybrid_Provider_Model
  1125. */
  1126. protected $_provider;
  1127. public function __construct()
  1128. {
  1129. $this->setSessionData() // retrieve data from current session
  1130. ->load() // load current user from DB
  1131. ->setEditor($this); // reference to self
  1132. }
  1133. /**
  1134. * Yes, it's current user - return always true
  1135. * NOTE: it's not user check, use isUser() instead!
  1136. * @return boolean
  1137. */
  1138. final public function isCurrent()
  1139. {
  1140. return true;
  1141. }
  1142. /**
  1143. * Get parent user ID - present if main admin is browsing
  1144. * front-end logged in as another user account
  1145. *
  1146. * @return integer or false if not present
  1147. */
  1148. final public function getParentId()
  1149. {
  1150. return $this->_parent_id;
  1151. }
  1152. /**
  1153. * Init external user login/signup provider
  1154. * @return e_system_user
  1155. */
  1156. public function initProvider()
  1157. {
  1158. if(null !== $this->_provider) return $this;
  1159. if($this->get('user_xup'))
  1160. {
  1161. $providerId = $this->getProviderName();
  1162. require_once(e_HANDLER.'user_handler.php');
  1163. $this->_provider = new e_user_provider($providerId);
  1164. $this->_provider->init();
  1165. }
  1166. }
  1167. /**
  1168. * Get external user provider
  1169. * @return Hybrid_Provider_Model
  1170. */
  1171. public function getProvider()
  1172. {
  1173. if(null === $this->_provider) $this->initProvider();
  1174. return $this->_provider;
  1175. }
  1176. /**
  1177. * Set external user provider (already initialized)
  1178. * @return e_user
  1179. */
  1180. public function setProvider($provider)
  1181. {
  1182. $this->_provider = $provider;
  1183. return $this;
  1184. }
  1185. /**
  1186. * Check if this user has assigned login provider
  1187. * @return boolean
  1188. */
  1189. public function hasProvider()
  1190. {
  1191. return ($this->getProvider() !== null);
  1192. }
  1193. /**
  1194. * User login
  1195. * @param string $uname
  1196. * @param string $upass_plain
  1197. * @param boolean $uauto
  1198. * @param string $uchallange
  1199. * @param boolean $noredirect
  1200. * @return boolean success
  1201. */
  1202. final public function login($uname, $upass_plain, $uauto = false, $uchallange = false, $noredirect = true)
  1203. {
  1204. if($this->isUser()) return false;
  1205. $userlogin = new userlogin();
  1206. $userlogin->login($uname, $upass_plain, $uauto, $uchallange, $noredirect);
  1207. $this->setSessionData(true)
  1208. ->setData($userlogin->getUserData());
  1209. return $this->isUser();
  1210. }
  1211. /**
  1212. * User login via external user provider
  1213. * @param string $xup external user provider identifier
  1214. * @return boolean success
  1215. */
  1216. final public function loginProvider($xup)
  1217. {
  1218. if(!e107::getPref('social_login_active', false)) return false;
  1219. if($this->isUser()) return true;
  1220. $userlogin = new userlogin();
  1221. $userlogin->login($xup, '', 'provider', false, true);
  1222. $this->setSessionData(true)
  1223. ->setData($userlogin->getUserData());
  1224. return $this->isUser();
  1225. }
  1226. /**
  1227. * Login as another user account
  1228. * @param integer $user_id
  1229. * @return boolean success
  1230. */
  1231. final public function loginAs($user_id)
  1232. {
  1233. // TODO - set session data required for loadAs()
  1234. if($this->getParentId()
  1235. || !$this->isMainAdmin()
  1236. || empty($user_id)
  1237. || $this->getSessionDataAs()
  1238. || $user_id == $this->getId()
  1239. ) return false;
  1240. $key = $this->_session_key.'_as';
  1241. if('session' == $this->_session_type)
  1242. {
  1243. $_SESSION[$key] = $user_id;
  1244. }
  1245. elseif('cookie' == $this->_session_type)
  1246. {
  1247. $_COOKIE[$key] = $user_id;
  1248. cookie($key, $user_id);
  1249. }
  1250. // TODO - lan
  1251. e107::getAdminLog()->log_event('Head Admin used Login As feature', 'Head Admin [#'.$this->getId().'] '.$this->getName().' logged in user account #'.$user_id);
  1252. //$this->loadAs(); - shouldn't be called here - loginAs should be called in Admin area only, loadAs - front-end
  1253. return true;
  1254. }
  1255. /**
  1256. *
  1257. * @return e_user
  1258. */
  1259. protected function _initConstants()
  1260. {
  1261. //FIXME - BC - constants from init_session() should be defined here
  1262. // [SecretR] Not sure we should do this here, it's too restricting - constants can be
  1263. // defined once, we need the freedom to do it multiple times - e.g. load() executed in constructor than login(), loginAs() etc.
  1264. // called by a controller
  1265. // We should switch to e.g. isAdmin() instead of ADMIN constant check
  1266. return $this;
  1267. }
  1268. /**
  1269. * Destroy cookie/session data, self destroy
  1270. * @return e_user
  1271. */
  1272. final public function logout()
  1273. {
  1274. if($this->hasProvider())
  1275. {
  1276. $this->getProvider()->logout();
  1277. }
  1278. $this->logoutAs()
  1279. ->_destroySession();
  1280. parent::destroy();
  1281. //if(session_id()) session_destroy();
  1282. e107::getSession()->destroy();
  1283. e107::setRegistry('core/e107/current_user', null);
  1284. return $this;
  1285. }
  1286. /**
  1287. * Destroy cookie/session/model data for current user, resurrect parent user
  1288. * @return e_user
  1289. */
  1290. final public function logoutAs()
  1291. {
  1292. if($this->getParentId())
  1293. {
  1294. // load parent user data
  1295. $this->_extended_model = $this->_parent_extmodel;
  1296. $this->_extended_structure = $this->_parent_extstruct;
  1297. $this->_user_config = $this->_parent_config;
  1298. if($this->_parent_model)
  1299. $this->setData($this->_parent_model->getData());
  1300. // cleanup
  1301. $this->_parent_id = false;
  1302. $this->_parent_model = $this->_parent_extstruct = $this->_parent_extmodel = $this->_parent_config = null;
  1303. }
  1304. $this->_destroyAsSession();
  1305. return $this;
  1306. }
  1307. public function tryProviderSession($deniedAs)
  1308. {
  1309. // don't allow if main admin browse front-end or there is already user session
  1310. if((!$deniedAs && $this->getSessionDataAs()) || null !== $this->_session_data || !e107::getPref('social_login_active', false)) return $this;
  1311. try
  1312. {
  1313. // detect all currently connected providers
  1314. $hybrid = e107::getHybridAuth(); // init the auth class
  1315. $connected = Hybrid_Auth::getConnectedProviders();
  1316. }
  1317. catch(Exception $e)
  1318. {
  1319. e107::getMessage()->addError('['.$e->getCode().']'.$e->getMessage(), 'default', true);
  1320. $session = e107::getSession();
  1321. $session->set('HAuthError', true);
  1322. $connected = false;
  1323. }
  1324. // no active session found
  1325. if(!$connected) return $this;
  1326. // query DB
  1327. $sql = e107::getDb();
  1328. $where = array();
  1329. foreach ($connected as $providerId)
  1330. {
  1331. $adapter = Hybrid_Auth::getAdapter($providerId);
  1332. if(!$adapter->getUserProfile()->identifier) continue;
  1333. $id = $providerId.'_'.$adapter->getUserProfile()->identifier;
  1334. $where[] = "user_xup='".$sql->escape($id)."'";
  1335. }
  1336. $where = implode(' OR ', $where);
  1337. if($sql->db_Select('user', 'user_id, user_password, user_xup', $where))
  1338. {
  1339. $user = $sql->db_Fetch();
  1340. e107::getUserSession()->makeUserCookie($user);
  1341. $this->setSessionData();
  1342. }
  1343. return $this;
  1344. }
  1345. /**
  1346. * TODO load user data by cookie/session data
  1347. * @return e_user
  1348. */
  1349. final public function load($force = false, $denyAs = false)
  1350. {
  1351. if(!$force && $this->getId()) return $this;
  1352. if(deftrue('e_ADMIN_AREA')) $denyAs = true;
  1353. // always run cli as main admin
  1354. if(e107::isCli())
  1355. {
  1356. $this->_load(1, $force);
  1357. $this->_initConstants();
  1358. return $this;
  1359. }
  1360. // NEW - new external user login provider feature
  1361. $this->tryProviderSession($denyAs);
  1362. // We have active session
  1363. if(null !== $this->_session_data)
  1364. {
  1365. list($uid, $upw) = explode('.', $this->_session_data);
  1366. // Bad cookie - destroy session
  1367. if(empty($uid) || !is_numeric($uid) || empty($upw))
  1368. {
  1369. $this->_destroyBadSession();
  1370. $this->_initConstants();
  1371. return $this;
  1372. }
  1373. $udata = $this->_load($uid, $force);
  1374. // Bad cookie - destroy session
  1375. if(empty($udata))
  1376. {
  1377. $this->_destroyBadSession();
  1378. $this->_initConstants();
  1379. return $this;
  1380. }
  1381. // we have a match
  1382. if(md5($udata['user_password']) == $upw)
  1383. {
  1384. // set current user data
  1385. $this->setData($udata);
  1386. // NEW - try 'logged in as' feature
  1387. if(!$denyAs) $this->loadAs();
  1388. // update lastvisit field
  1389. $this->updateVisit();
  1390. // currently does nothing
  1391. $this->_initConstants();
  1392. // init any available external user provider
  1393. if(e107::getPref('social_login_active', false)) $this->initProvider();
  1394. return $this;
  1395. }
  1396. $this->_destroyBadSession();
  1397. $this->_initConstants();
  1398. return $this;
  1399. }
  1400. return $this;
  1401. }
  1402. final public function loadAs()
  1403. {
  1404. // FIXME - option to avoid it when browsing Admin area
  1405. $loginAs = $this->getSessionDataAs();
  1406. if(!$this->getParentId() && false !== $loginAs && $loginAs !== $this->getId() && $loginAs !== 1 && $this->isMainAdmin())
  1407. {
  1408. $uasdata = $this->_load($loginAs);
  1409. if(!empty($uasdata))
  1410. {
  1411. // backup parent user data to prevent further db queries
  1412. $this->_parent_id = $this->getId();
  1413. $this->_parent_model = new e_user_model($this->getData());
  1414. $this->setData($uasdata);
  1415. // not allowed - revert back
  1416. if($this->isMainAdmin())
  1417. {
  1418. $this->_parent_id = false;
  1419. $this->setData($this->_parent_model->getData());
  1420. $this->_parent_model = null;
  1421. $this->_destroyAsSession();
  1422. }
  1423. else
  1424. {
  1425. $this->_parent_extmodel = $this->_extended_model;
  1426. $this->_parent_extstruct = $this->_extended_structure;
  1427. $this->_user_config = $this->_parent_config;
  1428. $this->_extended_model = $this->_extended_structure = $this->_user_config = null;
  1429. }
  1430. }
  1431. }
  1432. else
  1433. {
  1434. $this->_parent_id = false;
  1435. $this->_parent_model = null;
  1436. $this->_parent_extstruct = $this->_parent_extmodel = null;
  1437. }
  1438. return $this;
  1439. }
  1440. /**
  1441. * Update user visit timestamp
  1442. * @return void
  1443. */
  1444. protected function updateVisit()
  1445. {
  1446. // Don't update if main admin is logged in as current (non main admin) user
  1447. if(!$this->getParentId())
  1448. {
  1449. $sql = e107::getDb();
  1450. $this->set('last_ip', $this->get('user_ip'));
  1451. $current_ip = e107::getIPHandler()->getIP(FALSE);
  1452. $update_ip = $this->get('user_ip' != $current_ip ? ", user_ip = '".$current_ip."'" : "");
  1453. $this->set('user_ip', $current_ip);
  1454. if($this->get('user_currentvisit') + 3600 < time() || !$this->get('user_lastvisit'))
  1455. {
  1456. $this->set('user_lastvisit', (integer) $this->get('user_currentvisit'));
  1457. $this->set('user_currentvisit', time());
  1458. $sql->db_Update('user', "user_visits = user_visits + 1, user_lastvisit = ".$this->get('user_lastvisit').", user_currentvisit = ".$this->get('user_currentvisit')."{$update_ip} WHERE user_id='".$this->getId()."' ");
  1459. }
  1460. else
  1461. {
  1462. $this->set('user_currentvisit', time());
  1463. $sql->db_Update('user', "user_currentvisit = ".$this->get('user_currentvisit')."{$update_ip} WHERE user_id='".$this->getId()."' ");
  1464. }
  1465. }
  1466. }
  1467. final protected function _destroySession()
  1468. {
  1469. cookie($this->_session_key, '', (time() - 2592000));
  1470. unset($_SESSION[$this->_session_key]);
  1471. return $this;
  1472. }
  1473. final protected function _destroyAsSession()
  1474. {
  1475. $key = $this->_session_key.'_as';
  1476. cookie($key, '', (time() - 2592000));
  1477. $_SESSION[$key] = '';
  1478. unset($_SESSION[$key]);
  1479. return $this;
  1480. }
  1481. final protected function _destroyBadSession()
  1482. {
  1483. $this->_session_error = true;
  1484. return $this->_destroySession();
  1485. }
  1486. final public function getSessionDataAs()
  1487. {
  1488. $id = false;
  1489. $key = $this->_session_key.'_as';
  1490. if('session' == $this->_session_type && isset($_SESSION[$key]) && !empty($_SESSION[$key]))
  1491. {
  1492. $id = $_SESSION[$key];
  1493. }
  1494. elseif('cookie' == $this->_session_type && isset($_COOKIE[$key]) && !empty($_COOKIE[$key]))
  1495. {
  1496. $id = $_COOKIE[$key];
  1497. }
  1498. if(!empty($id) && is_numeric($id)) return intval($id);
  1499. return false;
  1500. }
  1501. final public function setSessionData($force = false)
  1502. {
  1503. if($force || null === $this->_session_data)
  1504. {
  1505. $this->_session_data = null;
  1506. $this->_session_key = e107::getPref('cookie_name', 'e107cookie');
  1507. $this->_session_type = e107::getPref('user_tracking', 'cookie');
  1508. if('session' == $this->_session_type && isset($_SESSION[$this->_session_key]) && !empty($_SESSION[$this->_session_key]))
  1509. {
  1510. $this->_session_data = &$_SESSION[$this->_session_key];
  1511. }
  1512. elseif('cookie' == $this->_session_type && isset($_COOKIE[$this->_session_key]) && !empty($_COOKIE[$this->_session_key]))
  1513. {
  1514. $this->_session_data = &$_COOKIE[$this->_session_key];
  1515. }
  1516. }
  1517. return $this;
  1518. }
  1519. public function hasSessionError()
  1520. {
  1521. return $this->_session_error;
  1522. }
  1523. final protected function _load($user_id)
  1524. {
  1525. $qry = 'SELECT u.*, ue.* FROM #user AS u LEFT JOIN #user_extended as ue ON u.user_id=ue.user_extended_id WHERE user_id='.intval($user_id);
  1526. if(e107::getDb()->db_Select_gen($qry))
  1527. {
  1528. return e107::getDb()->db_Fetch();
  1529. }
  1530. return array();
  1531. }
  1532. /**
  1533. * Not allowed
  1534. *
  1535. * @return e_user_model
  1536. */
  1537. final protected function setAsTarget()
  1538. {
  1539. return $this;
  1540. }
  1541. /**
  1542. * Not allowed
  1543. *
  1544. * @return e_user_model
  1545. */
  1546. final protected function clearTarget()
  1547. {
  1548. return $this;
  1549. }
  1550. public function destroy()
  1551. {
  1552. // not allowed - see logout()
  1553. }
  1554. }
  1555. class e_user_extended_model extends e_admin_model
  1556. {
  1557. /**
  1558. * Describes known model fields
  1559. * @var array
  1560. */
  1561. protected $_data_fields = array(
  1562. 'user_extended_id' => 'integer',
  1563. 'user_hidden_fields' => 'string',
  1564. );
  1565. /**
  1566. * @see e_model
  1567. * @var string
  1568. */
  1569. protected $_db_table = 'user_extended';
  1570. /**
  1571. * @see e_model
  1572. * @var string
  1573. */
  1574. protected $_field_id = 'user_extended_id';
  1575. /**
  1576. * @see e_model
  1577. * @var string
  1578. */
  1579. protected $_message_stack = 'user';
  1580. /**
  1581. * User class as set in user Adminsitration
  1582. *
  1583. * @var integer
  1584. */
  1585. protected $_memberlist_access = null;
  1586. /**
  1587. * @var e_user_extended_structure_tree
  1588. */
  1589. protected $_structure = null;
  1590. /**
  1591. * User model, the owner of extended fields model
  1592. * @var e_user_model
  1593. */
  1594. protected $_user = null;
  1595. /**
  1596. * Stores access classes and default value per custom field
  1597. * @var array
  1598. */
  1599. protected $_struct_index = array();
  1600. /**
  1601. * Constructor
  1602. * @param e_user_model $user_model
  1603. * @return void
  1604. */
  1605. public function __construct(e_user_model $user_model)
  1606. {
  1607. $this->_memberlist_access = e107::getPref('memberlist_access');
  1608. $this->setUser($user_model)
  1609. ->load();
  1610. }
  1611. /**
  1612. * Always return integer
  1613. */
  1614. public function getId()
  1615. {
  1616. return (integer) parent::getId();
  1617. }
  1618. /**
  1619. * Get user model
  1620. * @return e_user_model
  1621. */
  1622. public function getUser()
  1623. {
  1624. return $this->_user;
  1625. }
  1626. /**
  1627. * Set User model
  1628. * @param e_user_model $user_model
  1629. * @return e_user_exten…

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