Arbeiten mit dem User-Objekt

Für dynamische Anwendungen ist es unumgänglich spezielle Bereiche nur bestimmten Usern zugänglich zumachen. Hierfür muss ein User identifiziert und ggf. auch einer bestimmten Rolle zugewiesen werden. Drupal bietet einen komfortablen Registrierungs- und Loginprozess. Um mit diesen Daten zu arbeiten dient das User-Objekt. Auf den nächsten Seiten soll eine, in PHP, geschriebene Anwendung in Drupal imlementiert werden. Bei der Anwendung handelt es sich um ein Anwesenheitsmanagementsystem (Arbeitszeiterfassung). Hierfür wurden zwei zusätzliche Rollen angelegt: - Mitarbeiter - Leiter Verwaltung Der Mitarbeiter soll Zugriff auf seine eigenen Daten haben und einen Gruppenkalender einsehen können. Der Leiter Verwaltung hat die gleichen Rechte und kann zusätzlich auf die Mitarbeiterdaten zugreifen, Mitarbeiter anlegen und bearbeiten, Genehmigungen erteilen, usw... . Die Anwendung verfügt über eine eigene Datenbank und ein eigenes CSS-Design.

Auslesen des User-Objektes

Was steht nun in dem User-Objekt? Dazu lesen wir das Userobjekt erst einmal aus. Dazu verwenden wir erst einmal eine eigene Funktion, besser ist das Debugger-Modul zu verwenden, dazu aber später.

/**
* Startseite des AWS
*/
function aws_start()
{
// Holen des User-Objektes
global $user;  
$uebergabe = 'Start AWS';
$uebergabe .= '';  
$uebergabe .= array_auslesen($user);
 
return $uebergabe;
} // END aws_start  
 
/**
* Einfache Funktion zum Auslesen von Arrays
*/
function array_auslesen($array)
{
// Das Array auslesen
foreach($array as $key => $wert)
{
if(!is_array($wert))
$uebergabe .= $key.' - '.$wert.'
';
else
{
$uebergabe .= $key.' (
';  
$uebergabe .= array_auslesen($wert);  
$uebergabe .= ')
';
}
}  
 
return $uebergabe;
} // END array_auslesen

Ausgabe:
uid - 3
name - Mitarbeiter1
pass - cfe09803c312143de6ef0fe9dc436bc9
mail - mitarbeiter1@xxx.de
mode - 0
sort - 0
threshold - 0
theme -
signature -
created - 1208330988
access - 1208340810
login - 1208339914
status - 1
timezone -
language -
picture -
init -
mitarbeiter1@xxx.de
data - a:0:{}
sid - 8797c3216b5f0032fa1a38bda510e5f6
hostname - 127.0.0.1
timestamp - 1208340810
cache - 0
session -
roles (
2 - authenticated user
3 - Mitarbeiter
)

Hier die Definition der wichtigsten Punkte:

uid
Die User-ID des Users. Das ist der Primary-Key aus der Datenbank
name
Name des Users. Standardmäßig erfasst Drupal nur einen Namen und unterscheidet nicht Vor- bzw. Nachname.
pass
Das Passwort als MD5-Hash.
mail
Die Standard-Email-Adresse des Users.
status
Sollte eine 1 beinhalten, nur wenn der User gesperrt ist steht hier eine 0
data
Enthält ein serialisiertes Array in dem über die Funktion user_save() Daten hinterlegt werden können.
roles
Enthält ein Array mit den zugewiesenen Rollen. Es gibt zwei DEFAULT-Rollen
  1. anonymous user
  2. authenticated user
sid
Session ID
hostname
Die IP-Adresse

Über die Rolle wird im folgenden das weitere Menü gesteuert.

Benutzerabhängiges Menü

Als erstes soll unter dem Startmenü ein Menüpunkt erscheinen, der nur aktiv ist wenn ein User eingeloggt ist. Dafür gibt es zwei Möglichkeiten:

  1. Ein Admin-Menü erstellen in dem die Rechte der Sichtabrkeit über die Administrationsoberfläche in Drupal definiert werden können. Die Berechtigungen werden dann in der Drupal-eigenen Datenbank gespeichert.
  2. Die Berechtigungen in dem eigenen Modul setzen. (Das wird im Folgendem favorisiert)

Um einen ersten Menüpunkt zu erzeugen der nur für eingeloggte Mitarbeiter sichtbar ist, wird folgender Code verwendet:
/**
* Das Menüsystem des AWS
*/
function aws_menu()
{
// Holen des User-Objektes
global $user;
$items = array();
 
if(!$may_chache && ($user -> uid > 0))
{
$items[] = array
(
'path' => 'aws',
'title' =>t( 'Arbeitszeiten'),
'callback' => 'aws_helper',
'access' => true,
'type' => MENU_NORMAL_ITEM,
);
 
$items[] = array
(
'path' => 'aws/start',
'title' =>t( 'Arbeitszeit Start'),
'callback' => 'aws_start',
'access' => true,
'type' => MENU_NORMAL_ITEM,
);
}
 
return $items;
}

Anschließend wird der Menüpunkt in den Startpunkt verschoben (admin/build/menu). Solange der User nicht angemeldt ist, ist der Menüpunkt nicht sichtbar.

Erst nach der Anmeldung wird der neue Menüpunkt sichtbar. Hierzu sind zwei Dinge notwendig

  1. Einbinden des User-Objektes (global $user;).
  2. Abfragen ob ein User eingeloggt ist(if(!$may_chache && ($user -> uid > 0))).

User Login Bypass

Es kommt häufig vor das Daten schon in einer anderen Anwendung oder in einer anderen Datenbank liegen. Hier ist es nicht gewünscht alle Daten in Dupal zu integrieren, zumeist soll die externe Anwendung oder Datenbank genutzt werden. Drupal bietet dafür mehrere Möglichkeiten:

Externers Login via XML-RPC
Dazu verbindet sich Drupal mit einem externen Server und übergibt den Nutzernamen und das Passwort. Die Anwort ist ein TRUE oder FALSE. Bei Misserfolg können auch die Fehlermeldungen des kontaktierten Servers ausgegeben werden. Genaueres ist in der Dokumentation zu drupal_xmlrpc() nachzulesen. Bei Erfolg wird der User in die Tabelle {authmap} eingetragen.
Eigenes Script ohne User-Generierung
Hierbei wird die Authentifizierungsabfrage in Drupal um ein eigenes Script erweitert. Drupal wird dann nur mitgeteilt ob die Authentifizierung erfolgreich ist oder nicht. Drupal legt zwar einen eigenen User dafür an, aktiviert diesen aber nicht.
Eigenes Script mit User-Generierung
Hierbei wird die Authentifizierungsabfrage in Drupal um ein eigenes Script erweitert. Drupal wird dann nicht nur mitgeteilt ob die Authentifizierung erfolgreich ist oder nicht, sondern es wird gleichzeitig ein eigener User angelegt und aktiviert.

Es gibt noch eine Reihe fertiger Module mit denen die Authentifizierrung erledigt werden kann, z. B. das LDAP Integration um direkt auf eine Datenbank zuzugreifen. Generell schaut Drupal nur in der eigenen Datenbanktabelle {users} nach ob dort der User existiert, der sich grade versucht einzuloggen. Wenn dieser existiert wird das Passwort geprüft und geprüft ob der User aktiviert ist. Sind diese Prüfungen erfolgreich, werden die Userdaten geladen und im User-Objekt gespeichert. Damit sind dann auch die Berechtigungen global verfügbar. Es besteht jedoch auch die Möglichkeit einen eigenen Authentifizierungs-Mechanismus einzuhängen - (hook_auth()). Der Ablauf verändert sich dann ein wenig:

  1. Drupal schaut in die Tabelle {users}, findet er hier den aktivierten User - alles klar, dann wird abgebrochen und der User geladen.
  2. Drupal schaut in die Tabelle {authmap}, findet er hier den aktivierten User - alles klar, dann wird abgebrochen und der User geladen.
  3. Drupal schaut ob irgendwelche Module den hook_auth implementiert haben. Wenn nicht ist hier Schluss und der User wird abgewiesen.
  4. Drupal fragt den hook_auth nach seinem Ergebnis. Kommt hier ein FALSE ist Schluss und der User wird abgewiesen.
  5. Drupal legt den User an (falls er noch nicht existiert). An diesem Punkt kann auch in das User-Objekt eingegriffen werden.

Das Ergebnis ist dass der User jetzt im System angemeldet ist. Solange er kein aktiviertes Konto hat, stehen Ihm aber nicht alle Möglichkeiten offen.
/**
* Implementation des Hook_auth
*/
function aws_auth($username, $password, $server = FALSE)
{
drupal_set_message('Authentifikation - user:'.$username.' - pw:'.$password.' ist zugelassen');  
// Hier die Prüfung einbauen  
$return = true;  
 
return $return;
} // END aws_auth

 

Hier also ein "universeller" Bypass, der so natürlich nur lokal und nur zum Test verwendet werden sollte. Zumeist werden die Daten aus einer Datenbank geholt und Drupal mitgeteilt das der User Zugriff hat oder nicht. Wenn der User einen dauerhaften Zugriff auf das Drupal-System haben soll, besteht die Möglichkeit direkt einen Drupal-User anzulegen.
/**
* Implementation des Hook_auth
*/
function aws_auth($username, $password, $server = FALSE)
{
drupal_set_message('Authentifikation - user:'.$username.' - pw:'.$password.' ist zugelassen');  
 
// Hier die Prüfung einbauen und die Daten holen  
user_save('',
array
(
'name' => $username,
'pass' => $password,
'mail' => 'user@email.org',
'roles' => array
(2 => 'authenticated user', 3 => 'beliebige rolle'),
'status' => 1,
'init' => 'user@email.org',
)
);
 
$return = true;  
return $return;
} // END aws_auth

 

Mit der Methode user_save können die Daten direkt an Drupal gegeben und der User dort angelegt werden. Wird der erste Parameter mit der $user -> uid angegeben, wird kein neuer Account angelegt sondern geprüft ob ein Account vorhanden ist und dieser bei Bedarf upgedatet. Der zweite Parameter sind die Daten aus dem User-Objekt die als Array zurückgegeben werden. Man sollte sich allerdings immer die Frage stellen ob das sinnvoll ist, denn für diesen User existieren ja dann zwei Datensätze an unterschiedlichen Orten die auch gepflegt werden müssen.

User-Profilseite verändern

Die normale Profilseite eines Users in Drupal gibt nicht viel her. Man kann die Profile mit Drupal-Mitteln recht einfach erweitern und diese zusätzlichen Angaben auch ausgeben lassen. Dazu muss das Modul Profile (Dupal-Standardumfang) aktiviert werden und unter Verwalten -> Benutzerverwaltung können die Profile dann angepasst werden. Die Augabensteuerung und die Sichtbarkeiten für andere User sind alldings beschränkt. Daten aus externen Datenbanken oder Informationen die nicht im Profil sind können aber kaum ausgegeben werden.
Drupal Default-Userprofil
Hierfür kann aber über den hook_user($op, &$edit, &$account, $category = NULL) direkt die Inhalte zugegriffen werden. Der Zugriff erfolgt wieder in einem eigenen Modul. Es soll in diesem Beispiel erst einmal eine Adresse eingeblendet werden, die nicht im Drupal-System gespeichert ist. Es soll weiterhin eine Prüfung erfolgen ob der User auch die Berechtigung hat die Daten zu sehen.
<?php //; $ Id: manipulation.module, UwBach, 2008/05/14 $
 
/**
* @file Menümanipulation der Anwendung
* Erster Versuch
*/
 
/**
* Funktion um Usereinstellungen zu maipulieren
* Hier wird der gespeicherte Benutzername durch den richtigen Namen ersetzt, soweit er erfasst ist
*/
function manipulation_user($op, &$edit, &$user, $category = NULL)
{
// Wenn der User ein Profil aufruft
if($op == 'view')
{
// Der nachgefragte User
$requested_user = $user;
 
// Falls der User keine Berechtigung hat
if(!$user -> uid)
// Prüfung für Zugangsberechtigung einfügen oder weglassen
return ;
else
{
// hole irgendwelche Fremddaten
$externe_daten = array
(
'strasse' => 'Musterstrasse',
'hausnummer' => '12a',
'plz' => '12345',
'ort' => 'Testhausen'
);
}
 
// Der angemeldete User
global $user;  
 
// DEFAULT-Werte für die Sichtbarkeit der Angaben
$sichtbarkeit_adresse = FALSE;
 
// Falls der User seine eigenen Daten nachfragt - alles freigeben if($requested_user -> uid == $user -> uid)
{
$sichtbarkeit_adresse = TRUE;
} // Falls ein fremder Account nachgefragt wird - prüfen was freigegeben werden kann
else
{
// eigene Prüfung einfügen
} // Prüfen Ob die Adresse ausgeben werden soll
 
if($sichtbarkeit_adresse)
{
$items[] = array
(
'title' => t('Strasse'),
'value' => $externe_daten['strasse'],
'class' => 'adresse',
);  
 
$items[] = array
(
'title' => t('Hausnummer'),
'value' => $externe_daten['hausnummer'],
'class' => 'adresse',
);
 
$items[] = array
(
'title' => t('Postleitzahl'),
'value' => $externe_daten['plz'],
'class' => 'adresse',
);
 
$items[] = array
(
'title' => t('Ort'),
'value' => $externe_daten['ort'],
'class' => 'adresse',
);
 
return array
(
t('Adresse') => $items);
} // END  if($sichtbarkeit_adresse)
} // END if($op == 'view')  
} // END manipulation_user()

Die Ausgabe hat sich jetzt verändert:
geändertes Profil
Im Modul User Funktion user_user($type, &$edit, &$user, $category = NULL) wird die Default-Ausgabe generiert und kann ggf. überschrieben werden. Die Umsetzung des Arrays erfolgt in der Funktion function theme_user_profile($account, $fields) ebenfalls in dem Modul User. Interessant ist noch die Angabe 'class' mit der CSS-Klassen erzeugt werden. Der Quelltext sieht dann so aus:
<div class="profile">
<h2 class="title">Verlauf</h2>
<dl>
<dt class="user-member">Mitglied seit</dt>
<dd class="user-member">1 Woche 35 Minuten</dd>
</dl>
 
<h2 class="title">Adresse</h2>
<dl>
<dt class="manipulation-adresse">Strasse</dt>
<dd class="manipulation-adresse">Musterstrasse</dd>
<dt class="manipulation-adresse">Hausnummer</dt>
<dd class="manipulation-adresse">12a</dd>
<dt class="manipulation-adresse">Postleitzahl</dt>
<dd class="manipulation-adresse">12345</dd>
<dt class="manipulation-adresse">Ort</dt>
<dd class="manipulation-adresse">Testhausen</dd>
</dl>
</div>
Damit kann durch die Einbindung einer einfachen CSS-Datei das eigene Design schnell umgesetzt werden (siehe Kapitel "CSS einbinden").