theme_username woes

I got an email the other day informing me that a blog author on a site I had build could not post comments on his own blog. Authenticated users were not having the same problem, just the blog author. So using devel, I switched to his user account and tried it myself.

"You have to specify a valid author."

So I first dove into the access controls to make sure there wasn't something obvious that I had missed. Nothing. Then I scoured the source code for some mis-behaving form alter or something of the like. Nada. Then I hit google with the exact error message and landed at this post, and more specifically, this comment by rbarnes7.

The problem starts with this bit of code in comment_form():

<?php
function comment_form($edit, $title = NULL) {
  global
$user;
  ...
  if (
$user->uid) {
    if (
$edit['cid'] && user_access('administer comments')) {
      ...
    }
    else {
     
$form['_author'] = array('#type' => 'item', '#title' => t('Your name'), '#value' => theme('username', $user)
      );
     
$form['author'] = array('#type' => 'value', '#value' => $user->name);
    }
  }
?>

In my theme I had overridden theme_username to make use of information in the user profile created by bio.module.

<?php
function phptemplate_username($object) {
  if (
$object->uid && $object->name) {
    if(
$nid = bio_for_user($object->uid)){
     
$bio = node_load($nid);
     
$object->name = $bio->title;
    }

   
// Shorten the name when it is too long or it will break many tables.
   
if (drupal_strlen($object->name) > 20) {
     
$name = drupal_substr($object->name, 0, 15) .'...';
    }
    else {
     
$name = $object->name;
    }
    ...
?>

Only the 4 lines at the top of the function differ from the standard theme_username() function. From what I have seen, this is a pretty standard way to display a profile field (in this case, a bio node title). By simply swapping out the name property with the text that I want, the rest of the function does the rest of the work. And since the $object variable isn't specified to be passed by reference, overwriting the name property won't affect anything else... or so I thought.

The problem lies in the way that php handles global variables. When a variable is declared with the global keyword, it is a reference that you are using. The following are functionally equivalent:

<?php
 
global $user;
?>

and

<?php
  $user
= & $GLOBALS['user'];
?>

So in comment_form(), the call to theme('username', $user) is passing a reference to the global $user object, which means that any changes made to the object in the function take effect in the global scope.

The solution? Simply rewrite phptemplate_username to use a local variable to store the name.

<?php
function phptemplate_username($object) {
  if (
$object->uid && $object->name) {
    if(
$nid = bio_for_user($object->uid)){
     
$bio = node_load($nid);
     
$name = $bio->title;
    }
    else {
     
$name = $object->name;
    }
  
   
// Shorten the name when it is too long or it will break many tables.
   
if (drupal_strlen($name) > 20) {
     
$name = drupal_substr($name, 0, 15) .'...';
    }
    if (
user_access('access user profiles')) {
     
$output = l($name, 'user/'. $object->uid, array('title' => t('View user profile.')));
    }
    else {
     
$output = check_plain($name);
    }
  }
  ...
?>

0 Comments

    Post new comment

    • Web page addresses and e-mail addresses turn into links automatically.
    • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
    • Lines and paragraphs break automatically.

    More information about formatting options