Thứ Tư, 28 tháng 5, 2014

The $user Object [Working with Users]


Drupal requires that the user have cookies enabled in order to log in; a user with cookies turned off can still interact with Drupal as an anonymous user.

During the session phase of the bootstrap process, Drupal creates a global $user object that represents the identity of the
current user.  If the user  is not logged  in (and so does  not have a session cookie), then he or she is treated as an
anonymous user.  The code  that creates an anonymous user looks like this (and lives in includes/bootstrap.inc):

function  drupal_anonymous_user($session = '') {
$user  = new stdClass();
$user->uid = 0;
$user->hostname  = ip_address();
$user->roles = array();
$user->roles[DRUPAL_ANONYMOUS_RID]  = 'anonymous user';
$user->session = $session;
$user->cache = 0; return  $user;
}

On the other hand, if the user is currently logged  in, the $user object is created by joining the users table, roles, and  sessions
tables on the user’s ID. Values of all fields in both tables are placed into the $user object.

The $user object is easily inspected by adding global $user; print_r($user); to index.php. The following is what  a $user object
generally looks like for a logged-in user:

stdClass Object  ( [uid]  => 1[name]  =>  admin [pass] => $S$CnUvfOYdoxl/Usy.X/Y9/SCmOLLY6Qldrzjf7EOW0fR4LG7rCAmR [mail] => joe@example.com[theme]  => [signature]  => [signature_format] =>  0 [created] =>  1277957059 [access] =>  1278254230 [login] => 1277990573 [status] => 1 [timezone] => [language] => [picture] => 0[init] => joe@example.com[data] =>[sid] => 8cnG9e0jsCC7I7IYwfWB0rmRozIbaLlk35IQGN5fz9k [ssid] =>[hostname]  => ::1[timestamp]  => 1278254231 [cache]  => 0[session] => batches|a:1{i:3;b:1;} [roles] => Array
([2] => authenticated  user[3] => administrator)}

In the $user object just displayed, italicized field names denote that the origin  of the data is the sessions table. The components of
the $user object are explained in Table 6-1.

Component
Description
Provided by the users Table
uid
The user ID of this user.  This is the primary key of the users table and is unique to this Drupal installation.
name
The user’s username, typed by the user when logging in.
pass 
An sha512 hash of the user’s password, which is compared when the user logs in. Since the actual passwords aren’t saved,  they can only be reset  and  not restored.
mail
The user’s current e-mail address.
theme
This field is deprecated but left in the object for compatibility purposes.
signature
The signature the user entered on his or her account page.  Used when the user adds a comment and  only visible when the comment module is enabled.
Signature   format
The format of the users signature (e.g., filtered text, full text)
created
A Unix timestamp of when this user account was created.
access
A Unix timestamp denoting the user’s last access time.
login
A Unix timestamp denoting the user’s last successful login.
status
Contains 1 if the user is in good standing or 0 if the user has been blocked.
timezone
The number of seconds that the user’s time  zone  is offset from GMT.
language
The user’s default language. Empty unless multiple languages are enabled on a site and  the user has chosen a language by editing account preferences.
picture
The path to the image file the user has associated with the account.
init
The initial e-mail address the user provided when registering.
data
Arbitrary data can be stored here  by modules (see the next section, “Storing Data in the $user Object).
Provided by the user_roles Table
roles
The roles currently assigned to this user.
Provided by the sessions Table
sid
The session ID assigned to this user session by PHP.
Ssid
A secure session ID assigned to this user session by PHP.
hostname
The IP address from which the user is viewing the current page.
timestamp
A Unix timestamp representing time  at which the user’s browser last received a completed page.
cache
A timestamp used for per-user caching (see includes/cache.inc).
session
Arbitrary, transitory data stored for the duration of the user’s session can be stored here  by modules.


Testing If a User Is Logged In
During a request, the standard way of testing if a user is logged  in is to test whether $user->uid is 0.
Drupal has a convenience function called  user_is_logged_in() for this purpose (there is a corresponding user_is_anonymous()
function):

if (user_is_logged_in())
{
$output  = t('User is logged  in.'); 
else 
{
   $output  = t('User is an anonymous  user.');
}
}

Introduction to user hooks

Implementing user hooks gives your modules a chance to react to the different operations performed on a user account and  to
modify the $user object. There are several variants of hook_user, eac variant performing a specific action (see Table 6-2).

Table 6-2. hook user Functions
Hook function
Purpose
hook_username_alter(&$name, $account)
Alter the username that is displayed for the user.
hook_user_cancel($edit, $account, $method)
Act on user account cancellations.
hook_user_cancel_methods_alter(&$methods)
Modify an account cancellation method.
hook_user_categories()
Retrieve a list of user setting or profile information changes.
hook_user_delete($account)
Respond to user deletion.
hook_user_insert(&$edit, $account, $category)
A user account was created.
hook_user_load($users)
Act on user objects when loaded from the database.
hook_user_login(&$edit, $account)
The user just logged  in.
hook_user_logout($account)
The user just logged out.
hook_user_operations()
Add mass user operations.
hook_user_presave(&$edit, $account, $category)
A user account is about to be created or updated.
hook_user_role_delete($role)
Inform other modules that a user role has been deleted.
hook_user_role_insert($role)
Inform other modules that a user role has been added.
hook_user_role_update($role)
Inform other modules that a user role has been updated.
hook_user_update(&$edit, $account, $category)
A user account was updated.
hook_user_view($account, $viewmode)
The user’s account information is being displayed.
hook_user_view_alter(&$build)
The user was built; the module may modify the structured content.

Understanding hook_user_view($account, $view_mode)

hook_user_view() is used by modules to add information to user profile  pages (e.g., what  you see at http://example.com/?q=user/1; see Figure  6-1).

Figure 6-1. The user profile page, with the blog module and the user module implementing

hook_user_view() to add additional information

Lets examine how the blog module added its information to this page using  the hook_user_view function:
/**
*   Implements  hook_user_view().
*/
function  blog_user_view($account)  {
if (user_access('create  blog  content',  $account))  {
$account->content['summary' ['blog']  =   array( '#type'  => 'user_profile_item', '#title'  => t('Blog'), '#markup' => l(t('View  recent  blog  entries'), "blog/$account->uid", array('attributes' => array('title'  => t("Read  !username's  latest  blog  entries.",  array('!username' => format_username($account)))))),'#attributes' => array('class' => array('blog')),);}}

The view function stashes some information into $user->content. User profile  information is organized into categories,
with each  category representing a page of information about a user.  In Figure 6-1, there is just one category, called  History.
The outerarray should be keyed by category name. In the preceding example, the name of the key is summary, which corresponds
to the History category (admittedly, it would make more sense to name the key and  the category the same thing). The interior array(s)should have a unique textual key (blog in this case) and  have #type, #title, #markup, and #attributes elements. The type user_profile_item points Drupal’s theming layer to modules/user/user- profile-item.tpl.php. By comparing the code  snippet with
Figure 6-1, you can see how these elements are rendered. Listing 6-1 shows the contents of the $user->content array,
which became the page shown in Figure  6-1.
Listin 6-1. The Structure of $user->content
Array ([#pre_render] => Array ([0] => _field_extra_fields_pre_render)[#entity_type] => user [#bundle] => user [#attached] => Array([css] => Array ([0] => modules/field/theme/field.css))[summary] => Array ([blog] => Array([#type] => user_profile_item [#title] => Blog [#markup] => View recent blog  entries [#attributes] => Array([class] => Array ([0] => blog)))
[#type] => user_profile_category [#attributes] => Array([class] => Array ([0] => user-member))[#weight] => 5 [#title] => History [member_for]  => Array([#type] => user_profile_item [#title] => Member  for [#markup] => 3 days  11  hours))[user_picture] => Array ([#markup] => [#weight] => -10))

Your module may also implement hook_user_view() to manipulate the profile  items in the $user->content array  before they are
themed. The following is an example of simply  removing the blog profile item  from the user profile  page.  The function is named
as if it were in the hypothetical hide.module:
/**
*   Implements hook_user_view().
*/
function  hide_user_view($account, $view_mode = ‘full’)  { unset($account->content['summary']['blog']);}

The User Registration Process

By default, user registration on a Drupal site requires nothing more than a username an a valid e-mail address. Modules can add their own fields to the user registration form by implementing a few user hooks. Let’s write a module called  legalagree.module thatprovides a quick  way to make your site play well in today’s litigious society.
First, create a folder  at sites/all/modules/custom/legalagree, and  add the following files (see Listings 6-2 and  6-3) to the
legalagree directory.Then,  enable the module via Administer -> Site building -> Modules. 

Listin 6-2. legalagree.info
name = Legal  Agreement
description = Displays a  dubious  legal agreement  during  user  registration.
package  = Pro Drupal Development core  = 7.x
files[] = legalagree.module

Listin 6-3. legalagree.module
<?php
/**
*   @file
*   Support for  dubious  legal agreement  during  user  registration.
*/
/**
*      Implements hook_form_alter().
*/
function  legalagree_form_alter(&$form, &$form_state,  $form_id)  {
// check  to  see  if the  form is the  user  registration or  user  profile form
// if not  then  return  and don’t  do anything
if (!($form_id == 'user_register_form' || $form_id  == 'user_profile_form')) { return;}
// add a  new validate  function to  the  user  form to  handle  the  legal agreement
$form['#validate'][] = 'legalagree_user_form_validate';
// add a  field set to  wrap the  legal agreement
$form['account']['legal_agreement'] = array( '#type' => 'fieldset','#title' => t('Legal agreement'));
// add the  legal agreement  radio  buttons
$form['account']['legal_agreement']['decision'] = array( '#type' => 'radios','#description' => t('By registering at  %site-name, you agree  that at  any time, we (or  our  surly,  brutish henchmen) may  enter   your  place   of residence and
smash your  belongings with  a  ball-peen  hammer.', array('%site-name' => variable_get('site_name', 'drupal'))),
'#default_value' => 0,'#options' => array(t('I disagree'), t('I  agree')));}

/**
*   Form  validation handler  for  the  current   password on the  user_account_form().
*
*   @see user_account_form()
*/
function legalagree_user_form_validate($form, &$form_state)  {
global $user;
// Did user  agree?
if ($form_state['input']['decision'] <> 1)  {
form_set_error('decision', t('You   must agree  to  the  Legal  Agreement before   registration can  be  completed.'));
} 
else
{
     watchdog('user', t('User  %user agreed  to  legal  terms',  array('%user' => $user->name)));
}
}

The user  hook  gets called  during the creation of the registration form,  during the validation of that form, and  after the user
record has been inserted into the database. Our brief module will result in a registration form similar to the one shown in Figure 6-2.


Figure 6-2. A modified user registration form

Using profile.module to Collect User Information


If you plan  to extend the user  registration form to collect  information about users, you would do well to try out
profile.module before writing your own module. It allows you to create arbitrary forms to collect data, define whether the
information is requiredand/or collected on the user registration form, and designate whether the information is public or
private. Additionally, it allows the administrator to define pages so that users can be viewed  by their profile choices using a URL constructed from site URL plusprofile/ plus name of  profile field plus value.

For example, if you define a textual profile  field named profile_color, you could view all the users who chose black for their favorite color at http://example.com/?q=profile/profile_color/black. Or suppose you are creating a conference web site
and  areresponsible for planning dinner for attendees. You could define a check box profile  field named profile_vegetarian
and  view all users who are vegetarians at http://example.com/?q=profile/profile_vegetarian (note that for check box
fields, the value is implicitand  thus ignored; that is, there is no value appended to the URL like the value black was for theprofile_color field).

As a real-world example, the list of users at http://drupal.org who attended the 2010 Drupal conference in San Francisco,
California, can be viewed  at profile/conference-sf-2010 (in this case, the name of the field is not prefixed with profile_).


The Login Process


The login process begins when a user fills out the login form (typically at http://example.com/?q=user or 
displayed in a block)and  clicks the “Log in” button. The validation routines of the login form check whether the username has been blocked, whether an access rule has denied access, and  whether the user has entered an incorrect username or
password. The user is duly notified of any of these conditions.

Drupal attempts to log in a user  locally by searching for a row in the users table with the matching username and passwordhash. A successful login results in the firing of two user hooks (load and  login), which your modules can implement, as
shown in Figure  6-3.


Figure 6-3. Path of execution for a local user login

Adding Data to the $user Object at Load Time


The load operation of the user hook  is fired when a $user object is successfully loaded from the database in response to a call to user_load(). This happens when a user logs in, when authorship information is being retrieved for a node, and at
several other points.

Lets write a module named loginhistory that keeps a history of when the user logged in. We’ll display the number of times the user has logged in on the user’s “My account” page.  Create a folder named loginhistory in  sites/all/modules/
custom/, and add the files in Listings 6-4 through 6-6.First up is sites/all/modules/custom/loginhistory/loginhistory.info.

Listin 6-4. loginhistory.info
name = Login History
description = Keeps track  of  user  logins.
package  = Pro Drupal Development core  = 7.x
files[] = loginhistory.install files[] = loginhistory.module

We need an .install file to create the database table to store the login information, so we create sites/all/modules/custom/
loginhistory/loginhistory.install.

Listin 6-5. loginhistory.install
<?php
/**
*   Implements hook_schema().
*/
function loginhistory_schema() {
$schema['login_history'] = array('description' => 'Stores  information about  user  logins.', 'fields' => array(
'uid' => array( 'type'  => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'The  {user}.uid of the
user logging in.',),'login' => array( 'type'  => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'description' =>
'Unix  timestamp  denoting   time  of  login.',),),'indexes' => array( 'uid' => array('uid),),);
return  $schema;}

Listin 6-6. loginhistory.module

<?php
/**
*   @file
*   Keeps track  of  user  logins.
*/
/**
*   Implements hook_user_login
*/
function loginhistory_user_login(&$edit,  $account) {
// insert a  new record  each  time  the  user  logs in
$nid  = db_insert('login_history')->fields(array( 'uid' => $account->uid,
'login' => $account->login))->execute();}
/**
*   Implements hook_user_view_alter
*/
function loginhistory_user_view_alter(&$build){
global $user;
// count  the  number  of  logins for  the  user
$login_count = db_query("SELECT  count(*) FROM   {login_history} where uid  = :uid", array(':uid' => $user->uid))->fetchField();
// update  the  user  page  by adding  the  number  of  logins to  the  page
$build['summary'['login_history'] = array( '#type' => 'user_profile_item', '#title' => t('Number  of  logins'), '#markup' => $login_count, '#weight' => 10,);}

After installing this module, each  successful user login will fire the login operation of the hook_user_login, which the module will respond to by inserting a record into the login_history table in the database. When  the $user object is loaded duringhook_user_
view, the hook_user_view_alter function will be fired, and  the module will add  the current number of logins for that user to the page when the user views the “My account” page,  as shown in Figure  6-4.


Figure 6-4. Login history tracking user logins

Providing User Information Categories


If you have an account on http://drupal.org, you can see the effects of providing categories of user information by logging in and  clicking the My account” link, and  then selecting the Edit tab. In addition to editing your account information,
such as yourpassword, you can provide information about yourself in several other categories such as Drupal involvement,
personal information, work information, and preferences for receiving newsletters.

External Login

Sometimes, you may not want  to use Drupal’s local users table. For example, maybe you already have a table of users in another database or in LDAP. Drupal makes it easy to integrate external authentication into the login process.

Lets implement a very simple external authentication module to illustrate how external authentication works. Suppose your
company hires  only people named Dave, and  usernames are assigned based on first and  last names.
This module authenticates anyone whose username begins with the string dave, so the users davebrown, davesmith, and 
davejones will all successfully log in. Our approach will be to use form_alter() to alter the user login validation handler so that it runs our own validation handler. Here issites/all/modules/custom/authdave/authdave.info:

name  = Authenticate  Daves
description  = External  authentication  for  all  Daves.
package = Pro  Drupal  Development core  = 7.x
files[]  = authdave.module

And here  is the actual authdave.module:
<?php
/**
*   Implements  hook_form_alter().
*   We  replace  the  local  login  validation  handler  with  our own.
*/
function  authdave_form_alter(&$form,  &$form_state,  $form_id)  {
// In this  simple  example  we  authenticate  on username  to  see whether  starts  with  dave if ($form_id  == 'user_login'  || $form_id  == 'user_login_block')  {$form['#validate'][]  = 'authdave_user_form_validate';}}

/**
*   Custom  form  validation  function
*/
function  authdave_user_form_validate($form,  &$form_state)  { if (!authdave_authenticate($form_state))
{
        form_set_error('name',  t('Unrecognized  username.'));
}}
/**
*   Custom  user  authentication  function
*/
function  authdave_authenticate($form_state)  {
// get  the  first four  characters of  the  users   name
$username = $form_state['input']['name'];
$testname  = drupal_substr(drupal_strtolower($username),0,4);
// check  to  see  if the  person  is a  dave if ($testname == "dave")  {
// if it’s a  dave  then  use  the  external_login_register  function
// to  either log  the  person  in  or  create a  new account  if that
// person  doesn’t exist  as  a  Drupal user user_external_login_register($username, ‘authdave’); return  TRUE;
} else {
return  FALSE;}}
In the authdave module (see Figure  6-5), we simply swap out the second validation handler for our own.
Compare Figure  6-5 with Figure  6-3, which shows the local user login process.

Figure 6-5. Path of execution for external login with a second validation handler provided by
the authdave module (compare with Figure 6-3)

The function user_external_login_register() is a helper function that registers the user if this is the first login and  then logs the
user in. The path of execution is shown in Figure  6-6 for a hypothetical user davejones logging in for the first time.

If the username begins with dave” and  this is the first time  this user  has logged  in, a row in the users table does  not exist for
this user,  so one will be created. However, no e-mail address has been provided like it was for Drupal’s default local user
registration, so a module this simple is not a real solution if your site relies on sending e-mail to users.

You’ll want  to set the mail column of the users table  so you will have an e-mail address associated with the user.
To do this, you can have your modulerespond to the insert operation of the user hook,  which is fired whenever a new user is
inserted:

/**
*   Implements hook_user_insert().
*/
function  authdave_user_insert(&$edit, &$account,  $category = NULL)  global  $authdave_authenticated;
if ($authdave_authenticated) {
$email  = mycompany_email_lookup($account->name);
// Set  e-mail address  in  the  users   table for  this user.
db_update('users')->fields( array('mail' => $email,))->condition('uid',  $account->uid)->execute();}}

Savvy readers will notice that there is no way for the code  to tell whether the user is locally or externally authenticated, so we’ve
cleverly saved  a globa variable indicating that our module diauthentication. We could also have queried the authmaptable like so

db_query("SELECT  uid  FROM   {authmap} WHERE   uid  = :uid   AND  module = :module", array(':uid'=>$account
->uid,  'module'     => 'authdave');

All users who were added via external authentication will have a row in the authmap table  as well as the users table. However, in this case the authentication and  hook_user_insert run  during the same request, so a global variable is a good alternativeto a
database query.


Figure 6-6. Detail of the external user login/registration process

Summary


After reading this chapter, you should be able to

     Understand how users are represented internally in Drupal.

     Understand how to store information associated with a user in several ways.

     Hook into the user  registration process to obtain more information from a registering user.

     Hook into the user  login process to run  your own code  at user  login time.

     Understand how external user  authentication works.

     Implement your own external authentication module.
 For more information on external authentication, see the openid.module (part of the Drupal core) or the contributed
pubcookie.module.

Không có nhận xét nào:

Đăng nhận xét