This article is a coder’s apprentice guide to answering the question Who am I ? in drop all Drupal’s Content Management System, releases 5 and 6. While we’re at it, we’ll also answer the question Who is he or she ? with regards to any user — other than the one currently browsing the CMS. Finally, we’ll answer the question where are we ? as in : what is the “node” currently displayed on the page. Is there a node on the page, many, or none whatsoever ?
We can access a few variables from anywhere at anytime in Drupal, and the most important of these variables is $user. The object $user contains (almost) everything you’ll ever need to know about the user that is currently surfing the web site. This user may be logged in (a logged in registered user, hence), or he may be an anonymous user (not quite so anonymous because we can fetch his IP address, from the variable $user).
Whenever we want to access the global-scope $user variable for any purpose, we need to specify the variable’s scope, so we always need at least 2 lines of code to fetch information about the “user” :
// we are to access the content of the global-scope variable $user global $user; // salutation to the user print 'Hello, ' . $user->name;
For the sake of simplicity, we’re now printing words, like Hello how dow you do, without concern for the fact that they won’t be translatable to other languages. To make any text we print translatable, we use Drupal’s function t() — t as in translatable text, not t as in text. In both Drupal 5.x and Drupal 6.x, the placeholder in the t() function (used for dynamic content) is !variable for input that you generated, programmatically or otherwise (like a number, a 'role' name). Also use the !variable placeholder to print an e-mail address. Use the placeholder @variable for user input — anything you want Drupal to sanitize for you.
Using the function t(), the last code snippet becomes :
global $user; // salutation to the “user” print t('Hello, @user.', array('@user' => $user->name));
If we’re curious about the content of this variable, that is, if we want to answer the question what is there to learn from $user, we can use this call, which will print the entire content of the variable in a green box on our web page :
drupal_set_message('<pre>' . print_r($user, TRUE) . ' </pre>');
If we don’t set the second argument of the php function print_r
to TRUE, the content will be displayed above the web page’s header. You might actually prefer that.
The only information not provided by the omniscient $user is whatever user profile “info” was added through customizable fields created by the admin, using the Profile module, these fields that were labelled by the admin profile_{something}
. We’ll see how to access this information in a bit. We’ll also discover how to answer the question : do I have the right to {do-this} ? where do-this is one of the actions listed on the Permissions page. But first thing first, what does $user provide ? The user unique id, to begin with.
print $user->uid;
The user unique id is 0 for an anonymous visitor, 1 for the Administrator, and a value higher than 1 for a logged in visitor, it really is a unique value for each of the web’s site members (a.k.a users).
print $user->name; print $user->mail;
In the last bit, the property mail
provides the e-mail address of the logged in visitor.
Now this :
if(isset($user->signature)) { print $user->signature; }
The signature
of the user is specified in his/her profile, it may or may not be shown at the bottom of his comments depending on your default theme, and “admin” settings. Also, it may not have been set at all by the user.
print t('You registered !time ago.', array('!time' => format_interval(time() - $user->created)));
The last bit prints how long ago the user registered. Now, when was the last time the user accessed the web site ? The property login
gives us that information.
print t('Last time you logged in was !time ago.', array('!time' => format_interval(time() - $user->login)));
We might want to get an actual date on these things.
print t('You registered on !date.', array('!date' => format_date($user->created, 'small')));
You don’t like how the small
, medium
and long
dates are formatted in Drupal (always including the time in the day) ? Use a custom PHP format :
print t('You registered on !date.', array('!date' => format_date($user->created, 'custom', 'l, j M Y')));
The property hostname
gives us the user’s I.P. addy.
print t('Your IP address is !IP.', array('!IP' => $user->hostname));
We can show the user’s picture.The property $user->picture gives us the path to the user’s picture’s file, so we can display his/her picture on the page, like so:
if (isset($user->picture)) { $alt = $title = t('@name’s picture', array('@name' => $user->name)); print theme('image', $user->picture, $alt, $title); }
But we should never do it like that. Why? The path given to the user picture is the actual path. If you're using private download, your user image was uploaded to a private folder, probably not in your web site root. Hence, you need Drupal to get the image for you. Typing the actual path as 'src' attribute for the image won't work. The image will be broken. Unless of course the folder is IN your web site root. Say it is. Now, you've just revealed in your HTML markup where your not-so-private upload folder is. Bad idea.
It is preferable to use the Drupal function theme_user_picture() for the same purpose. It comes with a free gift as well. The user photo will be clickable. It will link to the user’s profile page. Depending on your website settings, visitors may not have access to the members' profile, so the picture may not be clickable for them.
if (isset($user->picture)) { print theme('user_picture', $user); }
Here is your face.
You are not logged in. So you cannot see yourself.
No one will be able to see your face here, but _you_ will. This posting is excecuting PHP code. That code fetches information from the global-scope variable $user, and that $user is yourself. When I view this post, I see my face.
Is there something else we can get from $user ? Certainly!
We can check which roles (possibly plural) the user has :
if (in_array('authenticated user', $user->roles)) { print t('You are an authenticated user.'); }
There is another way to check if a user has a specific role. The $user->roles
property is an array of strings, and when a certain indexed key is set, the user has the role associated with that indexed key. Authenticated user goes with index 2, and Anonymous user goes with index 1.
if (isset($user->roles[2])) { print t('You are an authenticated user.'); } if (isset($user->roles[1])) { print t('You are an anonymous user.'); }
If we want to know if the user has the right to, say, 'view uploaded files', then we check for this condition, from anywhere (not only from the module that defines such permission) :
if (user_access('view uploaded files')) { print t('You have the right to download files attachments.'); }
Drupal’s function user_access
informs us about the current user’s privileges, and it returns a boolean. If we want to know about another user’s privileges, we have to supply the function with a second argument. We will talk more about this in the next article.
If we want to fetch some user profile information, we first have to know the name of the profile field, that we added as an Administrator. That name begins with profile_
. If, for example, the profile field name was profile_about
, we would query the database like so :
SELECT column
FROM table1
JOIN table2
ON table1.foreign_key = table2.primary_key
WHERE table1.value = x AND WHERE table2.value = y
$result = db_query("SELECT pv.value FROM {profile_values} pv JOIN {profile_fields} pf ON pf.fid = pv.fid WHERE pv.uid = %d AND pf.name = '%s'", $user->uid, "profile_about"); if($about = db_fetch_object($result)) { print '<p>' . t('About @name : @value.', array( '@name' => $user->name, '@value' => $about->value, ) . '</p>'; }
Say we have someone’s unique user id (uid), or possess some other information about her, and we wish to collect additional information, and this user is not currently the user that’s logged in (or browsing the web site anonymously), then what do we do ? We use the Drupal function user_load(), companion function of node_load(). The function user_load()
returns a value of the same 'type' as the global-scope $user
variable. It returns an object (worth inspecting). We pass to the node_load() function an associative array containing some or all of the information we have regarding the user we are inquiring about.
// if we have his or her uid $thisUser = user_load(array('uid' => 6)); // if we have his or her name $thisUser = user_load(array('name' => 'Caroline Schnapp'));
Then we can fetch this user’s e-mail address, her last access time, etc.
print t('You can contact @name at <a href="mailto:!email">!email</a>.', array('@name' => $thisUser->name, '!email' => $thisUser->mail));
In the above example, we generated the markup of an anchor element ‘by hand’. We could have used Drupal’s function l() instead :
print t('You can contact @name at !emailURL.', array('@name' => $thisUser->name, '!emailURL' => l($thisUser->mail, 'mailto:' . $thisUser->mail)));
The function l() — l as in link — is usually invoked to generate markup for an internal Drupal link. If you’re not passing to it, as second argument, an internal path, then the function will understand the destination url if and only if it starts with a slash, ‘http’, ‘mailto’ or ‘ftp’. A link that starts with a slash ('/') is called a server-root-relative link, or an absolute link.
The above PHP code will generate the following XHTML markup :
You can contact John at <a href="mailto:john@john.c0m">john@john.c0m</a>.
We can determine when was the last time John visited our website :
print t('@name last visited us !time ago.', array('@name' => $thisUser->name, '!time' => format_interval(time() - $thisUser->login)));
Now, if we want to print the name of a user and make that printed name a link to his user’s page, what do we do ? We can write the anchor element markup by ‘hand’. We can use Drupal’s function l(). Or, we can use a Drupal function of which the sole purpose in life is to accomplish this. That function is a themeable function, meaning that a theme can override it to change what sort of markup is generated. The function is theme_username(). We pass to it a user object, not the user id (uid). The function returns the XHTML markup for the link to a user’s page.
$thisUser = user_load(array('uid' => 6)); print t('@name last visited us !time ago.', array('@name' => theme('username', $thisUser), '!time' => format_interval(time() - $thisUser->login)));
This php code will generate the following XHTML markup :
<a href="/user/6" title="View user profile.">John</a> last visited us 2 days ago.
If we want to know which privileges the user has, we use the function user_access(), and we set the second optional parameter to the $thisUser object.
$thisUser = user_load(array('uid' => $uid)); if (user_access('view uploaded files', $thisUser)) { ... }
Say we have a node ID (nid
), and we want to know who authored the Drupal node with that ID, and that author is not currently the user that’s logged-in, then we use the Drupal function node_load(). (The companion function to user_load()). The function node_load() either accepts a numerical value which is the nid of the node, OR it accepts an associative array containing information about the node, criteria against which the function will try to find a match, in the database. The function returns a node object. One property of this object is uid, that is, the user ID of the author of the node, and another is name, and that's the name of the author. Say we want to find the e-mail address of the author of node with node ID 25:
/* Using node_load with a node ID parameter */ $node = node_load(25); /* Then using user_load with the user ID */ $user = user_load(array('uid' => $node->uid)); print t('You may e-mail @name at !mailURL.', array( '@name' => $user->name, '!mailURL' => l($user->mail, 'mailto:' . $user->mail), ) );
Say we are in a block. Or say we are in a node’s body or teaser. We may ask ourselves : where am I ? On this page, whichever page, is there a node displayed ? If so, which node is it ? Or is there a list of nodes displayed ? If so, what kind of list is it ? Is it a list of nodes who share the taxonomy term “news” ? To answer these questions, one needs to understand Drupal’s path system. A brief recap :
In this article, I go into the details of Drupal’s concept of internal path and url alias. Note that 'system path' is another expression used for 'Drupal internal path'.
We use Drupal’s function arg()
to know the internal path of the page which is currently displayed. If the path to the page displayed is node/37/edit (corresponding to query http://myWebSite.com?q=node/37/edit), then arg(0)
returns "node"
, arg(1)
returns "37"
, and arg(2)
returns "edit"
. The function arg()
considers Drupal’s internal path, not the path alias you may see in the browser’s address bar. Say the web page displays one node with this path alias (pretty link) : "articles/how-to-scrub-your-bath", then what is shown in the browser’s address bar is http://myWebSite.com/articles/how-to-scrub-your-bath. However, arg(0)
won’t be equal to "articles"
and arg(1)
to "how-to-scrub-your-bath"
: instead, arg(0)
will return "node"
and arg(1)
the node id (nid) of the node displayed, for example "24"
.
While we are writing and executing php code in a node’s content or in a block, we have no concept of the current node(s) displayed on the page. We have no clue. It may seem strange that from the body of a node, we do not have direct access to the node id. As a matter of fact, a node doesn’t know itself, from its “body” (or teaser). The most direct approach to know where we are is to always use the function arg()
. Say we, as a node, i.e. node with nid 22, want to do something when we are displayed in full view (not just our teaser). Then, we, as a node, have to determine if we are indeed shown in full view, as convoluted as this may seem.
<?php
if (arg(0) == "node" && is_numeric(arg(1)) && arg(2) == NULL) {
echo t('We are viewing node %nodeNumber.',
array('%nodeNumber' => arg(1)));
if (arg(1) == 22) {
// do stuff
}
}
?>
Say I am in a block (I am writing code in a block), and I want to do something whenever a node is displayed in full view and is of the type book_review, I will go about finding out when I have to do my thing the following way :
<?php
if (arg(0) == "node" && is_numeric(arg(1)) && arg(2) == NULL) {
$thisNode = node_load(arg(1));
if ($thisNode->type == 'book_review') {
// do stuff
}
}
?>
You want to know what’s in a node object ? Examine one when it’s in full view. Create a block and, in it, type the following code snippet, and don’t forget to set the input format to php (and do not forget the php tags).
<?php
if (arg(0) == "node" && is_numeric(arg(1))) {
$thisNode = node_load(arg(1));
drupal_set_message('<pre>' .
print_r($thisNode, TRUE) .
' </pre>');
}
?>
We get the following information, and a lot more :
Property | Description |
---|---|
type | the type of node, for example story |
created | timestamp of creation time |
changed | timestamp of last time it was edited |
sticky | TRUE if it is sticky |
title | the title |
path | the path alias |
uid | user id of author |
name | name of author |
body | the content |
comment_count | the number of comments in it |
files | an array of file objects (file attachments) |
Here is a handy Drupal function that helps us determine if we are on the front page :
<?php
if(drupal_is_front_page()) {
echo t('We are on the front page.');
}
?>
We may need an abrupt redirect from where we are to somewhere else, if a certain condition evaluates to TRUE. For example, from a node’s body, we may want to redirect the user to the login page if he’s not logged in (that is a strange example, but no other comes to my mind right now).
<?php
global $user;
if(!$user->uid) {
drupal_goto('user');
}
?>
We may want to determine which menu item is currently active, if any. If we are viewing or previewing a node, the following function will return view ; if we are on the front page, it will return, oddly enough, Content. Getting the name of the current active menu item can be useful.
<?php
echo menu_get_active_title();
?>
We may want to set or get the page’s title. That will either be/become the title of the node or the title of the list of nodes... displayed on the page.
<?php
drupal_set_title('This page will change your life.');
?>
<?php
echo drupal_get_title(); // will return Content on the front page
?>
Say we want to determine if the current node displayed (if one is displayed) has, among its taxonomy terms, politics. We would like to set a block’s visibility with PHP, so that this block is visible whenever the current user is reading/viewing an article/blog about politics. In the 'Show block on specific pages settings', we will use the mode “Show if the following PHP code returns TRUE (PHP-mode, experts only)”. We have to return TRUE
if the current node is about politics.
How do we accomplish this? We have to determine if the page is displaying a node in full view; if that’s the case, then we have to determine if the node has in its taxonomy the term politics. We look at the database tables and realize that the information we need is in 2 tables, one table containing relationship info between tid (term id, a numerical value) and nodes — {term_node}, and another table providing information (including name) about terms — {term_data}. What connects both tables is the term id, i.e. tid. So, we’ll use a JOIN. In plain English, the following mySQL query does the following : trying to get a nid that is the one I am interested in (returned by arg(1)
) from the table {term_node} to which is associated the tid that has name politics, a name specified in table {term_data}.
SELECT column
FROM table1
JOIN table2
ON table1.foreign_key = table2.primary_key
WHERE table1.value = x AND WHERE table2.value = y
<?php
if (arg(0) == "node" && is_numeric(arg(1))) {
$result = db_query("SELECT tn.nid
FROM {term_node} tn
JOIN {term_data} td
ON tn.tid = td.tid
WHERE td.name = '%s'
AND tn.nid = %d",
'politics', arg(1));
if(db_fetch_object($result)) {
return TRUE;
}
else {
return FALSE;
}
}
?>
The attached pdf document explains the difference between :
In a nutshell, given that one types the following url in a browser’s address bar :
http://11heavens.com/Drupal-coder-lost-in-space/where-are-we
Based on rewrite rules found in the .htaccess file in the same folder as index.php, the server translates this url to :
http://11heavens.com/index.php?q=Drupal-coder-lost-in-space/where-are-we
The page index.php receives a name and value pair, where “q” is the name and “Drupal-coder-lost-in-space/where-are-we” is the value associated with that name.
Drupal looks up a url alias table — {url_alias} — and recognizes that this path is an alternate path for this Drupal’s internal path : node/44.
On the server, the page index.php builds its content based on that “internal path” and sends the xhtml back to the browser. In the browser is shown in full view the node with unique identifier 44.