Autodoc
  • Namespace
  • Class
  • Tree

Namespaces

  • BlueTihi
    • Context
  • Brickrouge
    • Element
      • Nodes
    • Renderer
    • Widget
  • ICanBoogie
    • ActiveRecord
    • AutoConfig
    • CLDR
    • Composer
    • Core
    • Event
    • Exception
    • HTTP
      • Dispatcher
      • Request
    • I18n
      • Translator
    • Mailer
    • Modules
      • Taxonomy
        • Support
      • Thumbnailer
        • Versions
    • Object
    • Operation
      • Dispatcher
    • Prototype
    • Routes
    • Routing
      • Dispatcher
    • Session
  • Icybee
    • ActiveRecord
      • Model
    • ConfigOperation
    • Document
    • EditBlock
    • Element
      • ActionbarContextual
      • ActionbarSearch
      • ActionbarToolbar
    • FormBlock
    • Installer
    • ManageBlock
    • Modules
      • Articles
      • Cache
        • Collection
        • ManageBlock
      • Comments
        • ManageBlock
      • Contents
        • ManageBlock
      • Dashboard
      • Editor
        • Collection
      • Files
        • File
        • ManageBlock
      • Forms
        • Form
        • ManageBlock
      • I18n
      • Images
        • ManageBlock
      • Members
      • Modules
        • ManageBlock
      • Nodes
        • ManageBlock
        • Module
      • Pages
        • BreadcrumbElement
        • LanguagesElement
        • ManageBlock
        • NavigationBranchElement
        • NavigationElement
        • Page
        • PageController
      • Registry
      • Search
      • Seo
      • Sites
        • ManageBlock
      • Taxonomy
        • Terms
          • ManageBlock
        • Vocabulary
          • ManageBlock
      • Users
        • ManageBlock
        • NonceLogin
        • Roles
      • Views
        • ActiveRecordProvider
        • Collection
        • View
    • Operation
      • ActiveRecord
      • Constructor
      • Module
      • Widget
    • Rendering
  • None
  • Patron
  • PHP

Classes

  • ActivateOperation
  • AvailableSitesBlock
  • ConfigBlock
  • ConfigOperation
  • DeactivateOperation
  • DeleteBlock
  • DeleteOperation
  • EditBlock
  • Hooks
  • IsUniqueOperation
  • LoginComboElement
  • LoginForm
  • LoginOperation
  • LogoutOperation
  • ManageBlock
  • Model
  • Module
  • OwnershipResolver
  • PermissionResolver
  • ProfileController
  • QueryOperationOperation
  • SaveOperation
  • UnlockLoginOperation
  • Update20131021
  • User
  • ViewProvider

Interfaces

  • OwnershipResolverInterface
  • PermissionResolverInterface

Traits

  • LoggedAtProperty

Exceptions

  • WebsiteAdminNotAccessible
  1 <?php
  2 
  3 /*
  4  * This file is part of the Icybee package.
  5  *
  6  * (c) Olivier Laviale <olivier.laviale@gmail.com>
  7  *
  8  * For the full copyright and license information, please view the LICENSE
  9  * file that was distributed with this source code.
 10  */
 11 
 12 namespace Icybee\Modules\Users;
 13 
 14 use ICanBoogie\ActiveRecord\CreatedAtProperty;
 15 use ICanBoogie\ActiveRecord\DateTimePropertySupport;
 16 use ICanBoogie\ActiveRecord\RecordNotFound;
 17 use ICanBoogie\DateTime;
 18 
 19 use Icybee\Modules\Users\Roles\Role;
 20 
 21 /**
 22  * A user.
 23  *
 24  * @property-read string $name The formatted name of the user.
 25  * @property-read boolean $is_admin true if the user is admin, false otherwise.
 26  * @property-read boolean $is_guest true if the user is a guest, false otherwise.
 27  * @property-read \Icybee\Modules\Users\Users\Role $role
 28  *
 29  * @property-read string $password_hash The password hash.
 30  * @property-read bool|null $has_legacy_password_hash Whether the password hash is a legacy hash.
 31  * {@link User::get_has_legacy_password_hash()}.
 32  *
 33  * @property \ICanBoogie\DateTime $logged_at The date and time at which the user was logged.
 34  */
 35 class User extends \ICanBoogie\ActiveRecord implements \Brickrouge\CSSClassNames
 36 {
 37     use \Brickrouge\CSSClassNamesProperty;
 38 
 39     const UID = 'uid';
 40     const EMAIL = 'email';
 41     const PASSWORD = 'password';
 42     const PASSWORD_HASH = 'password_hash';
 43     const USERNAME = 'username';
 44     const FIRSTNAME = 'firstname';
 45     const LASTNAME = 'lastname';
 46     const NICKNAME = 'nickname';
 47     const CREATED_AT = 'created_at';
 48     const LOGGED_AT = 'logged_at';
 49     const CONSTRUCTOR = 'constructor';
 50     const LANGUAGE = 'language';
 51     const TIMEZONE = 'timezone';
 52     const IS_ACTIVATED = 'is_activated';
 53     const ROLES = 'roles';
 54     const RESTRICTED_SITES = 'restricted_sites';
 55 
 56     const NAME_AS = 'name_as';
 57 
 58     /**
 59      * The {@link $name} property should be created from `$username`.
 60      *
 61      * @var int
 62      */
 63     const NAME_AS_USERNAME = 0;
 64 
 65     /**
 66      * The {@link $name} property should be created from `$firstname`.
 67      *
 68      * @var int
 69      */
 70     const NAME_AS_FIRSTNAME = 1;
 71 
 72     /**
 73      * The {@link $name} property should be created from `$lastname`.
 74      *
 75      * @var int
 76      */
 77     const NAME_AS_LASTNAME = 2;
 78 
 79     /**
 80      * The {@link $name} property should be created from `$firstname $lastname`.
 81      *
 82      * @var int
 83      */
 84     const NAME_AS_FIRSTNAME_LASTNAME = 3;
 85 
 86     /**
 87      * The {@link $name} property should be created from `$lastname $firstname`.
 88      *
 89      * @var int
 90      */
 91     const NAME_AS_LASTNAME_FIRSTNAME = 4;
 92 
 93     /**
 94      * The {@link $name} property should be created from `$nickname`.
 95      *
 96      * @var int
 97      */
 98     const NAME_AS_NICKNAME = 5;
 99 
100     /**
101      * User identifier.
102      *
103      * @var string
104      */
105     public $uid;
106 
107     /**
108      * Constructor of the user record (module id).
109      *
110      * The property MUST be defined to persist the record.
111      *
112      * @var string
113      */
114     public $constructor;
115 
116     /**
117      * User email.
118      *
119      * The property MUST be defined to persist the record.
120      *
121      * @var string
122      */
123     public $email;
124 
125     /**
126      * User password.
127      *
128      * The property is only used to update the {@link $password_hash} property when the
129      * record is saved.
130      *
131      * @var string
132      */
133     protected $password;
134 
135     protected function get_password()
136     {
137         return $this->password;
138     }
139 
140     protected function set_password($password)
141     {
142         $this->password = $password;
143 
144         if ($password)
145         {
146             $this->password_hash = $this->hash_password($password);
147         }
148     }
149 
150     /**
151      * User password hash.
152      *
153      * Note: The property MUST NOT be private, otherwise only instances of the class can be
154      * initialized with a value, for subclasses instances the property would be `null`.
155      *
156      * @var string
157      */
158     protected $password_hash;
159 
160     /**
161      * Checks if the password hash is a legacy hash, and not a hash created by
162      * the {@link \password_hash()} function.
163      *
164      * @return bool|null `true` if the password hash is a legacy hash, `false` if the password
165      * hash was created by the {@link \password_hash()} function, and `null` if the passsword hash
166      * is empty.
167      */
168     protected function get_has_legacy_password_hash()
169     {
170         if (!$this->password_hash)
171         {
172             return;
173         }
174 
175         return $this->password_hash[0] != '$';
176     }
177 
178     /**
179      * Username of the user.
180      *
181      * The property MUST be defined to persist the record.
182      *
183      * @var string
184      */
185     public $username;
186 
187     /**
188      * First name of the user.
189      *
190      * @var string
191      */
192     public $firstname = '';
193 
194     /**
195      * Last name of the user.
196      *
197      * @var string
198      */
199     public $lastname = '';
200 
201     /**
202      * Nickname of the user.
203      *
204      * @var string
205      */
206     public $nickname = '';
207 
208     /**
209      * Prefered format to create the value of the {@link $name} property.
210      *
211      * @var string
212      */
213     public $name_as = self::NAME_AS_USERNAME;
214 
215     use CreatedAtProperty;
216     use LoggedAtProperty;
217 
218     /**
219      * Prefered language of the user.
220      *
221      * @var string
222      */
223     public $language = '';
224 
225     /**
226      * Prefered timezone of the user.
227      *
228      * @var string
229      */
230     public $timezone = '';
231 
232     /**
233      * State of the user account activation.
234      *
235      * @var bool
236      */
237     public $is_activated = false;
238 
239     /**
240      * Defaults `$model` to "users".
241      *
242      * Initializes the {@link $constructor} property with the model identifier if it is not
243      * defined.
244      *
245      * @param string|\ICanBoogie\ActiveRecord\Model $model
246      */
247     public function __construct($model='users')
248     {
249         parent::__construct($model);
250 
251         if (empty($this->constructor))
252         {
253             $this->constructor = $this->model_id;
254         }
255     }
256 
257     public function __get($property)
258     {
259         $value = parent::__get($property);
260 
261         if ($property === 'css_class_names')
262         {
263             new \Brickrouge\AlterCSSClassNamesEvent($this, $value);
264         }
265 
266         return $value;
267     }
268 
269     protected function alter_persistent_properties(array $properties, \ICanBoogie\ActiveRecord\Model $model)
270     {
271         if ($this->get_created_at()->is_empty)
272         {
273             $this->set_created_at('now');
274         }
275 
276         /*
277         if ($this->get_updated_at()->is_empty)
278         {
279             $this->set_updated_at('now');
280         }
281         */
282 
283         return parent::alter_persistent_properties($properties, $model);
284     }
285 
286     /**
287      * Adds the {@link $logged_at} property.
288      */
289     public function to_array()
290     {
291         $array = parent::to_array();
292 
293         if ($this->password)
294         {
295             $array['password'] = $this->password;
296         }
297 
298         return $array;
299     }
300 
301     /**
302      * Returns the formatted name of the user.
303      *
304      * The format of the name is defined by the {@link $name_as} property. The {@link $username},
305      * {@link $firstname}, {@link $lastname} and {@link $nickname} properties can be used to
306      * format the name.
307      *
308      * This is the getter for the {@link $name} magic property.
309      *
310      * @return string
311      */
312     protected function get_name()
313     {
314         $values = [
315 
316             self::NAME_AS_USERNAME => $this->username,
317             self::NAME_AS_FIRSTNAME => $this->firstname,
318             self::NAME_AS_LASTNAME => $this->lastname,
319             self::NAME_AS_FIRSTNAME_LASTNAME => $this->firstname . ' ' . $this->lastname,
320             self::NAME_AS_LASTNAME_FIRSTNAME => $this->lastname . ' ' . $this->firstname,
321             self::NAME_AS_NICKNAME => $this->nickname
322 
323         ];
324 
325         $rc = isset($values[$this->name_as]) ? $values[$this->name_as] : null;
326 
327         if (!trim($rc))
328         {
329             return $this->username;
330         }
331 
332         return $rc;
333     }
334 
335     /**
336      * Returns the role of the user.
337      *
338      * This is the getter for the {@link $role} magic property.
339      *
340      * @return \Icybee\Modules\Users\Users\Role
341      */
342     protected function lazy_get_role()
343     {
344         global $core;
345 
346         $permissions = [];
347         $name = null;
348 
349         foreach ($this->roles as $role)
350         {
351             $name .= ', ' . $role->name;
352 
353             foreach ($role->perms as $access => $permission)
354             {
355                 $permissions[$access] = $permission;
356             }
357         }
358 
359         $role = new Role();
360         $role->perms = $permissions;
361 
362         if ($name)
363         {
364             $role->name = substr($name, 2);
365         }
366 
367         return $role;
368     }
369 
370     /**
371      * Returns all the roles associated with the user.
372      *
373      * This is the getter for the {@link $roles} magic property.
374      *
375      * @return array
376      */
377     protected function lazy_get_roles()
378     {
379         global $core;
380 
381         try
382         {
383             if (!$this->uid)
384             {
385                 return [ $core->models['users.roles'][1] ];
386             }
387         }
388         catch (\Exception $e)
389         {
390             return [];
391         }
392 
393         $rids = $core->models['users/has_many_roles']->select('rid')->filter_by_uid($this->uid)->all(\PDO::FETCH_COLUMN);
394 
395         if (!in_array(2, $rids))
396         {
397             array_unshift($rids, 2);
398         }
399 
400         try
401         {
402             return $core->models['users.roles']->find($rids);
403         }
404         catch (RecordNotFound $e)
405         {
406             trigger_error($e->getMessage());
407 
408             return array_filter($e->records);
409         }
410     }
411 
412     /**
413      * Checks if the user is the admin user.
414      *
415      * This is the getter for the {@link $is_admin} magic property.
416      *
417      * @return boolean `true` if the user is the admin user, `false` otherwise.
418      */
419     protected function get_is_admin()
420     {
421         return $this->uid == 1;
422     }
423 
424     /**
425      * Checks if the user is a guest user.
426      *
427      * This is the getter for the {@link $is_guest} magic property.
428      *
429      * @return boolean `true` if the user is a guest user, `false` otherwise.
430      */
431     protected function get_is_guest()
432     {
433         return !$this->uid;
434     }
435 
436     /**
437      * Returns the ids of the sites the user is restricted to.
438      *
439      * This is the getter for the {@link $restricted_sites_ids} magic property.
440      *
441      * @return array The array is empty if the user has no site restriction.
442      */
443     protected function lazy_get_restricted_sites_ids()
444     {
445         global $core;
446 
447         return $this->is_admin ? [] : $core->models['users/has_many_sites']->select('siteid')->filter_by_uid($this->uid)->all(\PDO::FETCH_COLUMN);
448     }
449 
450     /**
451      * Checks if the user has a given permission.
452      *
453      * @param string|int $permission
454      * @param mixed $target
455      *
456      * @return mixed
457      */
458     public function has_permission($permission, $target=null)
459     {
460         global $core;
461 
462         if ($this->is_admin)
463         {
464             return Module::PERMISSION_ADMINISTER;
465         }
466 
467         return $core->check_user_permission($this, $permission, $target);
468     }
469 
470     /**
471      * Checks if the user has the ownership of an entry.
472      *
473      * If the ownership information is missing from the entry (the 'uid' property is null), the user
474      * must have the ADMINISTER level to be considered the owner.
475      *
476      * @param $module
477      * @param $record
478      *
479      * @return boolean
480      */
481     public function has_ownership($module, $record)
482     {
483         global $core;
484 
485         return $core->check_user_ownership($this, $record);
486     }
487 
488     /**
489      * Hashes a password.
490      *
491      * @param string $password
492      *
493      * @return string
494      */
495     static public function hash_password($password)
496     {
497         return \password_hash($password, \PASSWORD_BCRYPT);
498     }
499 
500     /**
501      * Compares a password to the user's password hash.
502      *
503      * @param string $password
504      *
505      * @return bool `true` if the hashed password matches the user's password hash,
506      * `false` otherwise.
507      */
508     public function verify_password($password)
509     {
510         if (\password_verify($password, $this->password_hash))
511         {
512             return true;
513         }
514 
515         #
516         # Trying old hashing
517         #
518 
519         $config = \ICanBoogie\Core::get()->configs['user'];
520 
521         if (empty($config['password_salt']))
522         {
523             return false;
524         }
525 
526         return sha1(\ICanBoogie\pbkdf2($password, $config['password_salt'])) == $this->password_hash;
527     }
528 
529     /**
530      * Logs the user in.
531      *
532      * A user is logged in by setting its id in the `application[user_agent]` session key.
533      *
534      * Note: The method does *not* checks the user authentication !
535      *
536      * The following things happen when the user is logged in:
537      *
538      * - The `$core->user` property is set to the user.
539      * - The `$core->user_id` property is set to the user id.
540      * - The session id is regenerated and the user id, ip and user agent are stored in the session.
541      *
542      * @return boolean true if the login is successful.
543      *
544      * @throws \Exception in attempt to log in a guest user.
545      *
546      * @see \Icybee\Modules\Users\Hooks\get_user_id
547      */
548     public function login()
549     {
550         global $core;
551 
552         if (!$this->uid)
553         {
554             throw new \Exception('Guest users cannot login.');
555         }
556 
557         $core->user = $this;
558         $core->user_id = $this->uid;
559         $core->session->regenerate_id(true);
560         $core->session->regenerate_token();
561         $core->session->users['user_id'] = $this->uid;
562 
563         return true;
564     }
565 
566     /**
567      * Log the user out.
568      *
569      * The following things happen when the user is logged out:
570      *
571      * - The `$core->user` property is unset.
572      * - The `$core->user_id` property is unset.
573      * - The `$core->session->users['user_id']` property is unset.
574      */
575     public function logout()
576     {
577         global $core;
578 
579         unset($core->user);
580         unset($core->user_id);
581         unset($core->session->users['user_id']);
582     }
583 
584     /**
585      * Returns the CSS class names of the node.
586      *
587      * @return array[string]mixed
588      */
589     protected function get_css_class_names()
590     {
591         return [
592 
593             'type' => 'user',
594             'id' => ($this->uid && !$this->is_guest) ? 'user-id-' . $this->uid : null,
595             'username' => ($this->username && !$this->is_guest) ? 'user-' . $this->username : null,
596             'constructor' => 'constructor-' . \ICanBoogie\normalize($this->constructor),
597             'is-admin' => $this->is_admin,
598             'is-guest' => $this->is_guest,
599             'is-logged' => !$this->is_guest
600 
601         ];
602     }
603 }
604 
605 /**
606  * Implements the`logged_at` property.
607  *
608  * @property \ICanBoogie\DateTime $logged_at The date and time at which the user was logged.
609  */
610 trait LoggedAtProperty
611 {
612     /**
613      * The date and time at which the user was logged.
614      *
615      * @var mixed
616      */
617     private $logged_at;
618 
619     /**
620      * Returns the date and time at which the user was logged.
621      *
622      * @return \ICanBoogie\DateTime
623      */
624     protected function get_logged_at()
625     {
626         return DateTimePropertySupport::datetime_get($this->logged_at);
627     }
628 
629     /**
630      * Sets the date and time at which the user was logged.
631      *
632      * @param mixed $datetime
633      */
634     protected function set_logged_at($datetime)
635     {
636         DateTimePropertySupport::datetime_set($this->logged_at, $datetime);
637     }
638 }
Autodoc API documentation generated by ApiGen 2.8.0