Manage a community of users
Create site15 by copying site14.
- /cms
- ...
- site14
- site15
In this chapter, we are going to manage a community of users in a DB and grant them roles.
To test the result online, enter http://www.frasq.org/cms/site15 in the address bar of your navigator.
Connect as foobar
with the password f00bar
.
A green button with a check appears in the banner of the home page.
If you click it, the content of the page is transmitted to the W3C's validator.
Disconnect and reconnect as barfoo
with the password barf00
.
The link to the W3C isn't displayed.
Start the command processor of MySQL and enter the site's DB:
$ mysql -u root -p
mysql> use frasqdb2;
NOTE: Use phpMyAdmin for more comfort.
Add the table user
to the site's DB:
user_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(40) NOT NULL,
`password` VARCHAR(32) NOT NULL,
mail VARCHAR(100) DEFAULT NULL,
created datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`access` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
locale enum('fr','en') NOT NULL DEFAULT 'fr',
active tinyint(1) NOT NULL DEFAULT '1',
banned tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (user_id),
UNIQUE KEY name (name),
UNIQUE KEY mail (mail)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
The primary key user_id
is also the user's number.
name
and mail
are unique keys which allow the identification of a user.
password
contains the user's password encrypted in MD5.
created
keeps the creation date and time of the account.
access
records the date and time of the last connection to the account.
locale
gives the user's preferred language among the ones managed by the site.
active
indicates if the account is accessible.
banned
signals a user who is undesirable.
Create a user foobar
with the password f00bar
and a user barfoo
with the password barf00
:
VALUES ('foobar', MD5('f00bar'), 'foobar@localhost', NOW());
INSERT INTO USER (name, password, mail, created)
VALUES ('barfoo', MD5('barf00'), 'barfoo@localhost', NOW());
Notice that the passwords are encoded in MD5. IMPORTANT: Never keep passwords in clear text.
Add the tables role
and user_role
to the site's DB:
role_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(40) NOT NULL,
PRIMARY KEY (role_id),
UNIQUE KEY name (name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
role
is nothing more than a list of names.
user_id INT(10) UNSIGNED NOT NULL DEFAULT '0',
role_id INT(10) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (user_id,role_id),
KEY `role` (role_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
user_role
associates a user to a role. A user can have several roles.
Define the roles administrator
, writer
, reader
and moderator
:
INSERT INTO `role` (name) VALUES ('writer');
INSERT INTO `role` (name) VALUES ('reader');
INSERT INTO `role` (name) VALUES ('moderator');
Associate the user foobar
to the roles administrator
and writer
:
INSERT INTO user_role (user_id, role_id) VALUES (1, 2);
Check that you can list the role names of a user:
mysql> SELECT u.name AS user_name, r.name AS role_name FROM user u
JOIN user_role ur ON ur.user_id=u.user_id
JOIN role r ON r.role_id=ur.role_id
WHERE ur.user_id=1;
+-----------+---------------+
| user_name | role_name |
+-----------+---------------+
| foobar | administrator |
| foobar | writer |
+-----------+---------------+
2 rows in set (0.00 sec)
mysql> quit
Edit the file user.inc
in the folder models
and add the following functions:
- function user_get($user_id) {
- if (!is_numeric($user_id)) {
- return false;
- }
- $tabuser=db_prefix_table('user');
- $sql="SELECT name AS user_name, password AS user_password, mail AS user_mail, UNIX_TIMESTAMP(created) AS user_created, UNIX_TIMESTAMP(access) AS user_access, locale AS user_locale, active AS user_active, banned AS user_banned FROM $tabuser WHERE user_id=$user_id LIMIT 1";
- $r = db_query($sql);
- return $r ? $r[0] : false;
- }
user_get
returns an array with the fields user_name
user_password
, user_mail
, user_created
, user_access
, user_locale
, user_active
and user_banned
of the user whose number is $user_id
or false
if $user_id
isn't a valid user number.
- function user_get_role($user_id) {
- if (!is_numeric($user_id)) {
- return false;
- }
- $tabrole=db_prefix_table('role');
- $tabuserrole=db_prefix_table('user_role');
- $sql="SELECT r.name AS role_name FROM $tabuserrole ur JOIN $tabrole r ON r.role_id=ur.role_id WHERE ur.user_id=$user_id";
- $r = db_query($sql);
- if (!$r) {
- return false;
- }
- $role=array();
- foreach ($r as $v) {
- $role[] = $v['role_name'];
- }
- return $role;
- }
user_role
returns the list of the roles of the user $user_id
or false
if $user_id
isn't a valid user number.
- function user_find($login) {
- $sqllogin=db_sql_arg($login, true);
- $tabuser=db_prefix_table('user');
- $sql="SELECT user_id FROM $tabuser WHERE name=$sqllogin OR mail=$sqllogin LIMIT 1";
- $r = db_query($sql);
- return $r ? $r[0]['user_id'] : false;
- }
user_find
checks if a user whose name or email address is $login
is defined in the DB.
user_find
returns the user's unique number or false
in case of failure.
- function user_login($login, $password) {
- $user_id = user_find($login);
- if (!$user_id) {
- return false;
- }
- $r = user_get($user_id);
- if (!$r) {
- return false;
- }
- extract($r); /* user_name user_password user_mail user_created user_access user_locale user_active user_banned */
- if (!$user_active or $user_banned) {
- return false;
- }
- $password=md5($password);
- if ($password != $user_password) {
- return false;
- }
- $now=time();
- $user = array();
- $user['id'] = $user_id;
- $user['name'] = $user_name;
- $user['mail'] = $user_mail;
- $user['locale'] = $user_locale;
- $user['created'] = (int)$user_created;
- $user['access'] = $now;
- $r = user_get_role($user_id);
- $user['role'] = $r;
- $tabuser=db_prefix_table('user');
- $sql="UPDATE $tabuser SET access=FROM_UNIXTIME($now) WHERE user_id=$user_id LIMIT 1";
- db_update($sql);
- return $user;
- }
user_login
obtains the number of the user whose name or email address is $login
with user_find
, then all the properties of the account with user_get
.
If $login
isn't the name or the email address of a user or if $password
doesn't match the password or if the account is inactive or blocked, user_login
returns false
.
If the connection is accepted, $login
writes down the date and the time in the DB before returning an array with the fields id
, name
, mail
, locale
, created
and access
extracted from the array returned by user_get
and the field role
containing the list of roles returned by user_get_role
.
Notice that the interface to the user_login
function hasn't changed. Therefore you don't need to modify the form of the identification page.
Enter http://localhost/cms/site15/en/user in the address bar of your navigator and check that everything is like before.
Add the file userhasrole.php
in the folder library
with the following content:
- /cms/site15
- library
- userhasrole.php
- library
- function user_has_role($role) {
- return isset($_SESSION['user']) and $_SESSION['user']['role'] and in_array($role, $_SESSION['user']['role']);
- }
user_has_role
returns true
if the user is connected and if $role
is one of her roles, or false
otherwise.
Modify the banner
function which builds the block of the banner of the site in the file banner.php
in the folder blocks
:
- require_once 'userhasrole.php';
Loads the function user_has_role
.
- $menu=$contact=$login=$logout=$validate=false;
- $languages=false;
- $user_page=$contact_page=$nobody_page=$validate_page=false;
- $is_identified = user_is_identified();
- $is_writer = user_has_role('writer');
Initializes the variables $validate
and $validate_page
.
Sets $is_writer
to true
if the user has the role writer
, to false
if not.
- case 'validate':
- if ($param) {
- if ($is_writer) {
- $validate_page=$param;
- $validate=true;
- }
- }
- break;
If 'validate'
is in $components
, if $param
isn't false
and if $is_writer
is true
, assigns the value associated to the component to $validate_page
and sets $validate
to true
.
- if ($logout or $contact) {
- $menu = view('bannermenu', $lang, compact('contact', 'contact_page', 'validate', 'validate_page', 'logout', 'nobody_page', 'login', 'user_page'));
- }
Passes the parameters $validate
and $validate_page
to the view.
Modify the home
action in the file home.php in the folder actions to pass the link to the W3C to the banner block:
- $validate=url('home', $lang);
- $banner = build('banner', $lang, compact('languages', 'contact', 'account', 'validate'));
Assign the URL of the home page to $validate
and passes the parameter to banner
.
Add the link to the validator to the view of the menu of the banner in the files views/en/bannermenu.phtml for the English version and views/fr/bannermenu.phtml for the French version:
- <?php if (isset($validate) and $validate): ?>
- <li><a id="validate" href="http://validator.w3.org/check?uri=<?php echo $base_root . $validate_page; ?>" target="validator.w3.org" title="Validate"><span>Valider</span></a></li>
- <?php endif; ?>
- <?php if (isset($validate) and $validate): ?>
- <li><a id="validate" href="http://validator.w3.org/check?uri=<?php echo $base_root . $validate_page; ?>" target="validator.w3.org" title="Valider"><span>Valider</span></a></li>
- <?php endif; ?>
Modify the style sheet to display a button instead of a link to the W3C:
- #bannermenu #validate {width:24px;height:24px;float:left;margin-right:6px;background:transparent url(../buttons/check.png) no-repeat center center;}
Copy the icon in the folder buttons:
- /cms/site14
- buttons
- check.png
- buttons
Enter http://localhost/cms/site15 in the address bar of your navigator.
Connect as foobar
with the password f00bar
.
Check that the validation button is displayed on the home page.
Disable the CSS to evaluate the quality of the generated document.
Move the mouse over the button to control the URL.
If your site is accessible on the web, click on the button to validate the content of the page.
Connect as barfoo
with the password barf00
.
Check that the validation button isn't displayed on the home page.
Comments