I would like to create pages containing lists of all the registered users.

These pages should be only viewable by authenicated users or users in a certain roles group.

How can I do this?

Thank you.

Comments

AjK’s picture

Create a page using the "PHP code" input format. Then use something like this (it's just a sample to get you started)

global $user;

if (!$user->uid || !in_array('role name', $user->roles)) {
  print 'Access denied';
}
else {
  $r = db_query('SELECT name FROM {users} WHERE status != 0 ORDER BY name');
  print '<ul>';
  while ($row = db_fetch_object($r)) {
    print '<li>'. $row->name .'</li>';
  }
  print '</ul>';
}
jdevries’s picture

In the above snippet, make sure to replace 'role name' with an array of user roles that are allowed to view the page. Also note that you should probably also restrict this item in a menu system from showing up to anonymous users. Otherwise they will get the access denied page from a menu item link, which is not the most elegant solution.

I am currently experimenting with a table based user list. This table assumes you have a real name and a country field added to the profiles. Also note that this code is not checking permissions, you can write it in from the above example. In my case everybody can look through the user list. However, depending on your access settings it determines whether or not a link to the user profiles is made, or if simply a plain text is shown with the username.

<?php
// Displays a list of all users including their profile images (all roles)

$header = array(
  array('data' => t('Avatar'), 'field' => 'u.avatar'),
  array('data' => t('User'), 'field' => 'u.name', 'sort' => 'asc'),
  array('data' => t('Real name'), 'field' => 'u.realname'),
  array('data' => t('Country'), 'field' => 'u.country')
);
$sql = 'SELECT u.uid, u.name, u.status, u.created, u.access FROM {users} u WHERE uid != 0 AND uid != 6';
$sql .= tablesort_sql($header);
$result = pager_query($sql, 50);

$status = array(t('blocked'), t('active'));
while ($account = db_fetch_object($result)) {
       $account = user_load(array('uid' => $account->uid));
       if($account->picture){$account->picture = '<img src="'.$account->picture.'" height="25" width="25" border="1" alt="">';}
         else{$account->picture = '<img src="files/pictures/default.gif" height="25" width="25" border="1" alt="">';}

$rows[] = array($account->picture, theme('username', $account), $account->profile_realname, $account->profile_country);
}

$output = theme('table', $header, $rows);
$output .= theme('pager', NULL, 50, 0);
print ($output);
?>

This code was altered from the last example on this page. I'm still trying to figure out how to replace the sortable headers with static headers (unsortable list) though.

AjK’s picture

This code was altered from the last example on this page. I'm still trying to figure out how to replace the sortable headers with static headers (unsortable list) though.

If you don't want any sortable headers just remove the $sql .= tablesort_sql($header); and don't include any 'field' definitions in the $header array. If you want to just sort by, say for example, "Real name" remove the 'field' definitions from the other array elements and leave array('data' => t('Real name'), 'field' => 'u.realname'), as is (and keep the $sql .= tablesort_sql($header); in).

jdevries’s picture

Works like a charm, thanks!

polar-bear’s picture

Sorting with the u.name works fine but sorting with name in profile field does not work for me.

My code which is listed below generates an error.

<?php
// Displays a list of all users including their profile images (all roles)

$header = array(
  array('data' => t('User'), 'field' => 'u.name'),
  array('data' => t('Real Name'), 'field' => 'u.name_us', 'sort' => 'asc'),
  array('data' => t('Company'), 'field' => 'u.job_org'),
  array('data' => t('Job Title'), 'field' => 'u.job_position') 
);
$sql = 'SELECT * FROM {users} u WHERE uid != 0 AND uid != 6';
$sql .= tablesort_sql($header);
$result = pager_query($sql, 50);

$status = array(t('blocked'), t('active'));
while ($account = db_fetch_object($result)) {
       $account = user_load(array('uid' => $account->uid));
if($account->name!="kseauksigp") {$rows[] = array(theme('username', $account), $account->profile_name_us, $account->profile_job_org, $account->profile_job_position);}
}

$output = theme('table', $header, $rows);
$output .= theme('pager', NULL, 50, 0);
print ($output);
?>
user warning: Unknown column 'u.name_us' in 'order clause' query: SELECT * FROM sig_p_users u WHERE uid != 0 AND uid != 6 ORDER BY u.name_us ASC LIMIT 0, 50 in /home/kseauk.org/public_html/sig-p/includes/database.mysql.inc on line 167.

Could someone offer me any advice on this, please?

Thank you.

AjK’s picture

If you want to list/search by profile values you need to JOIN your {users} table......

// Displays a list of all users including their profile images (all roles)

$header = array(
  array('data' => t('User'), 'field' => 'u.name'),
  array('data' => t('Real Name'), 'field' => 'u.name_us', 'sort' => 'asc'),
  array('data' => t('Company'), 'field' => 'pf.job_org'),
  array('data' => t('Job Title'), 'field' => 'pf.job_position') 
);
$sql = 'SELECT * FROM {users} u '.
         'INNER JOIN {profile_values} pv ON pv.uid = u.uid '.
         'INNER JOIN {profile_fields} pf ON pf.fid = pv.fid '.
         'WHERE u.uid != 0';
$sql .= tablesort_sql($header);
$result = pager_query($sql, 50);

...

Something like that. I suggest you look at the profile_fields and profile_values tables and see how they join with the users table (profile_values has a field called uid which joins that value to a user uid and fid that joins it to the profile_field table fid)

AjK’s picture

and I should point you to the reason for your error also. You can't invent field names that don't exist.

  array('data' => t('Real Name'), 'field' => 'u.name_us', 'sort' => 'asc'),
  $sql = 'SELECT * FROM {users} u WHERE uid != 0 AND uid != 6';

'field' should hold the name of a field value that your SQL is going to return. What is u.name_us supposed to be? That isn't returned by your SQL. I'm guessing that you have a profile value called name_us. That being the case, you'll need to join as I explained and then use the correct col field name in your sort criteria (eg pf.name_us)

AjK’s picture

I just had a quick go at doing this and realise it's more tricky than you think. The JOINed SQL I show above will return multiple rows per user (one row for each profile value). The code you show goes on to use user_load() to get the details. The problem is this, in order to use tablesort_sql() to produce a sortable table you need to make sure your SQL produces one row per table row (and not bother with the user_load() at all).

So, a straight table of users is fine but if you want a sortable list, you're going to have to sit down and design what you want rather than hacking away at a snippet. Tricky stuff ;) Possible but you need to think it through carefully. Sorry, I don't have the time to do it myself now, I have too many things on my plate ;)

What it boils down to is this. When using tablesort_sql() with theme('table') there should be a one to one relationship with SQL rows returned and table rows displayed. In order to get one row you can build the row with some array stuff. I just tried that and it "sort of" worked. The problem is you then need to make sure your profile values are always in the same order. But you can't do this as tablesort_sql() will alter them depending upon which col you are sorting on. Basically, I think you can create what you want but I don't think you'll be able to sort by profile value quite so easily (if at all).

jdevries’s picture

Please note where the sql statement says "WHERE uid != 0 AND uid != 6". This prevents user accounts 0 (anonymous) and 6 (in my case a special admin account) from showing up in the list. Omitting the "AND uid != 6" should be used if you only want to surpress the anonymous user.

ktonini’s picture

how could i modify this code to just display the current users avatar?

syngi’s picture

I picked up the code here some days ago and struggled with the sorting issue too. Then I saw that the views module can sort on profile.module fields, so I checked the code. And finally with some help from gnari at #mysql@irc.freenode.net I managed to get it to work!

Personally I needed an 'address book'. A list of users searchable on fields which were added by profile.module (then still sortable). So the code does just that :)

I didn't turn it into a module, because I don't have the time. Should someone be able to pick it up from here please do! I tried to make the code as flexible as I could, so I believe that turning it into a module shouldn't be that hard.

To 'configure' the script, just change the arrays $columns and $search_buttons at the top to specify what columns you want to show and be able to search on.
What's not (yet - hint hint ;)) configurable is the restriction to the search criteria I have added to force it to be no less than 2 character; and the WHERE clause that excludes the first 3 users + the blocked onces from the search.


$columns = array(
  array('data' => 'Titel', 'field' => 'profile_algemeen_titel'),
  array('data' => 'Voorletters', 'field' => 'profile_algemeen_voorletters'),
  array('data' => 'Achternaam', 'field' => 'profile_algemeen_achternaam', 'sort' => 'asc'),
  array('data' => 'Plaatsnaam', 'field' => 'profile_prive_plaats'),
  array('data' => 'Bekijk profiel')
);
$search_buttons = array(
  array('name' => 'naam', 'field' => 'profile_algemeen_achternaam'),
  array('name' => 'plaats', 'field' => 'profile_prive_plaats')
);


$addressbook_search = (!isset($_POST['addressbook_search']['reset']) ? $_REQUEST['addressbook_search'] : '');

print '<form method="post" action="?q=' . drupal_get_path_alias($_GET['q']) . ($_GET['sort'] ? '&sort=' . $_GET['sort'] : '') . ($_GET['order'] ? '&order=' . $_GET['order'] : '') . '" id="addressbook_form"><fieldset>';
print '<input type="text" name="addressbook_search[criteria]" id="addressbook_search[criteria]" value="' . ($addressbook_search['criteria'] ? $addressbook_search['criteria'] : t('Enter value')) . '" onclick="if(this.defaultValue == this.value){this.value = \'\';}" onblur="if(this.value.replace(/^\s+|\s+$/g, \'\') == \'\'){this.value = this.defaultValue}" />';
print '<span id="addressbook_form_delimiter">&raquo;</span>';

foreach ($search_buttons as $button) {
  print ' <input type="submit" value="' . $button['name'] . '" name="addressbook_search[column][' . $button['field'] . ']" class="addressbook_search_column ' . $button['field'] . '" />';
}
if ($addressbook_search) {
  print '<input type="image" title="' . t('Show all users') . '" src="' . $imagePath . '/addressbook_reset.gif" name="addressbook_search[reset]" id="addressbook_search_reset" />';
}

print '</fieldset></form>';

if (!$GLOBALS['user']->uid || !in_array('authenticated user', $GLOBALS['user']->roles)) {
  print t('Access denied');
}
else {

  $sql_columns = $sql_joins = '';
  foreach ($columns as $column) {
    if ($column['field']) {
      $sql_columns .= ', ' . $column['field'] . '.value AS ' . $column['field'];
      $sql_joins .= ' LEFT JOIN {profile_values} ' . $column['field'] . ' ON ' . $column['field'] . '.fid = (SELECT fid FROM {profile_fields} WHERE name = "' . $column['field'] . '") AND users.uid = ' . $column['field'] . '.uid';
    }
  }
  $sql = 'SELECT users.uid' . $sql_columns . ' FROM {users}' . $sql_joins . ' WHERE users.uid > 4 AND status = 1';

  if ($addressbook_search['criteria']) {
    if (strlen($addressbook_search['criteria']) < 3) {
      print t('Please enter at least 2 characters.');
    }
    else {
      foreach ($addressbook_search['column'] as $column => $value) {
        $sql .= ' AND ' . $column . '.value LIKE "%s%%"';
      }

      $sql .= tablesort_sql($columns);
      $result = pager_query($sql, 50, 0, NULL, $addressbook_search['criteria']);
    }
  }
  else
  {
    $sql .= tablesort_sql($columns);
    $result = pager_query($sql, 50);
  }

  if ($result) {
    $rows = array();
    while ($account = db_fetch_array($result)) {

      unset($account['uid']);
      $account[] = '<a href="?q=user/' . $account->uid . '">profile</a>';
      $rows[] = $account;
    }

    if (count($rows) > 0) {
      print theme('table', $columns, $rows, array('id' => 'addressbook_table'));
      print theme('pager', NULL, 50);
    }
    else {
      print t('No users were found.');
    }
  }

}

Sorry about the inline javascript, but that's also because of the lack of time...

Several classnames and IDs are used, so the script is themeable. Some example CSS :

#addressbook_form {
  position: relative;
  margin-bottom: 26px;
}

.addressbook_search_column {
  margin-left: 6px;
}

#addressbook_search_reset {
  position: absolute;
  right: 12px;
  top: 13px;
}

#addressbook_table
{
}

#addressbook_table tr.odd
{
}
#addressbook_table tr.even
{
  background-color: #E5E5E5;
}

#addressbook_table td
{
  padding-right: 16px;
}

.pager
{
  margin-top: 16px;
}

The icon used for the reset button can be found at http://www.saulmade.nl/forum/addressbook_reset.png or as a gif blended on a white bg http://www.saulmade.nl/forum/addressbook_reset.gif .

Paul

syngi’s picture

I forgot to wrap the profile link in t() and I worked with account as it was fetched as an object (changed that later on to array). Also the unset need to come after using uid...

Change :

      unset($account['uid']);
      $account[] = '<a href="?q=user/' . $account->uid . '">t(profile)</a>';

into

      $account[] = '<a href="?q=user/' . $account['uid'] . '">' . t('profile') . '</a>';
      unset($account['uid']);
syngi’s picture

and of course the permisson check, if you want it, should go before the form:

 if (!$GLOBALS['user']->uid || !in_array('authenticated user', $GLOBALS['user']->roles)) {
  print t('Access denied');
}
{ 

should be moved to before

$addressbook_search = (!isset($_POST['addressbook_search']['reset']) ? $_REQUEST['addressbook_search'] : '');

syngi’s picture

The query, by the way, will result in this code when using the setting (arrays) I posted above:

SELECT
 users.uid,
 profile_algemeen_titel.value AS profile_algemeen_titel,
 profile_algemeen_voorletters.value AS profile_algemeen_voorletters,
 profile_algemeen_achternaam.value AS profile_algemeen_achternaam,
 profile_prive_plaats.value AS profile_prive_plaats
 FROM users
 LEFT JOIN profile_values profile_algemeen_titel ON profile_algemeen_titel.fid = (SELECT fid FROM profile_fields WHERE name = 'profile_algemeen_titel') AND users.uid = profile_algemeen_titel.uid
 LEFT JOIN profile_values profile_algemeen_voorletters ON profile_algemeen_voorletters.fid = (SELECT fid FROM profile_fields WHERE name = 'profile_algemeen_voorletters') AND users.uid = profile_algemeen_voorletters.uid
 LEFT JOIN profile_values profile_algemeen_achternaam ON profile_algemeen_achternaam.fid = (SELECT fid FROM profile_fields WHERE name = 'profile_algemeen_achternaam') AND users.uid = profile_algemeen_achternaam.uid
 LEFT JOIN profile_values profile_prive_plaats ON profile_prive_plaats.fid = (SELECT fid FROM profile_fields WHERE name = 'profile_prive_plaats') AND users.uid = profile_prive_plaats.uid
 WHERE users.uid > 4 AND status = 1
# AND profile_prive_plaats.value LIKE 'Bruss%'

with the braked last line being added when you search on location (Dutch:'Plaatsnaam') 'Bruss' for 'Brussels' for example...