Webdesign in Siegen

Binäres Rechtesystem

Fragen zum Thema PHP können hier gestellt werden

Moderator: Basti

Binäres Rechtesystem

Beitragvon Avedo am 20.07.2008, 00:57

Guten Morgen!
Ich stehe mal wieder vor einem größeren Problem. Jeder kennt ihn, den Stress mit der Benutzerverwaltung und dem damit verbundenen Rechtesystem. Früher habe ich einfach in der User-Tabelle eine Spalte rights gehabt, in der durch Komma getrennt die Bereiche standen, die der User betreten darf. Leider ist diese Variante sehr Performance fressend und erfordert eine weitere Tabelle in der alle verfügbaren Bereiche des internen Bereichs stehen, um die Rechte auch ändern zu können. Daher bin ich sehr schnell auf die Variante umgestiegen, bei der in einer Tabelle einerseits das Recht, dass der User besitzt und der jeweilige User stehen. Das heißt für jeden User mehrere Einträge in dieser Tabelle, es sei denn er besitzt überhaupt keine. Aber auch diese Variante erscheint mir nicht als die optimalste.

Da fiel mir das UNIX- oder auch Datei-Rechtesystem (chmod) ein. Beide bauen auf dem binären Zahlensystem auf. Die möglichen Rechte beim Zugriff auf Dateien sind euch vermutlich bekannt. Lesen, Schreiben und Ausführen (die Unterscheidung in Besitzer, Gruppen und Öffentliche Berechtigungen lassen wir außer Acht). Diesen drei Rechten wurden Zweierpotenzen zugewiesen.
Ausführen => 1 (2^0)
Schreiben => 2 (2^1)
Lesen => 4 (2^2)
Durch addieren der einzelnen Rechte kann man alle Rechte eines Users auf eine Zahl zusammenführen. Administratoren dürfen ja bekanntlich alles (=1+2+4=7) wohingegen andere User zum Beispiel nur Lesen und Schreiben dürfen (=2+4=6). Das besondere an einem binären Rechtesystem ist nun, dass man aus dieser Zahl (anders als beim Dezimalsystem) wieder alle Rechte extrahieren kann. Dies wird klarer wenn man die drei Zahlen für Lesen, Schreiben und Ausführen ins Binärsystem (Zählung von rechts) übersetzt.
Ausführen => 001
Schreiben => 010
Lesen => 100
Der Administrator besitzt also die rechte 111 und der vorhin erwähnte User 110.

Ein auf dieser Idee aufbauendes Rechtesystem wäre sehr Performance freundlich und würde nur zwei Tabellen erfordern. Die User-Tabelle mit einer Spalte permissions oder perms (Rechte) und eine Tabelle permissions, die alle geschützten Bereiche und das jeweils benötigte Recht (eine Zweierpotenz) beinhaltet. PHP bietet uns auch schon durch die binären Operatoren eine wundervolle Möglichkeit zur Überprüfung, ob ein Benutzer die nötigen Rechte besitzt. Es ist nämlich möglich über das &-Zeichen eine binäre UND-Verknüpfung zu schaffen. Mit Hilfe dieser Operation kann man zum Beispiel nun feststellen, ob an der dritten Stelle (Zählung von rechts) der binären Zahl, die die rechte eines Users stehen, eine Eins steht, die dem User im obigen Beispiel das Lesen erlauben würde.

Genug aber der Theorie. Da ich nun in neueren Projekten auf ein binäres Rechtesystem bauen möchte, habe ich mir vorgenommen eine Klasse zu schreiben, die mir dies ermöglicht. Bisher habe ich nur eine Grundstruktur und würde bevor es mit dem Coden richtig los geht gerne noch einige Meinungen und Anregungen einholen, um diese Klasse zu verbessern und zum Beispiel auch in einem Modul basierten System einsetzbar zu machen. Würde mich sehr über viele Antworten freuen.
MfG, Andy

Permissions.php
Code: Alles auswählen
<?php 
error_reporting(E_ALL);

/***
* Permissions class allows handling access rights

* @package Permissions
* @version 0.1
* @author Andreas Wilhelm <Andreas2209@web.de>
* @copyright Andreas Wilhelm
**/ 
class Permissions
{
   // important class variables
   protected $db;   
   
   /**
   * Cunstructor - Connects to user-table
   *
   * @access public
   * @param Str $path
   * @return boolean
   */
   public function __construct(Sql $db, $table, $field)
   {
      $this->db = $db;      
   }

   /**
   * addPerm() - Adds a new protected area
   *
   * @access public
   * @param Int $name
   * @param Int $perm
   * @return Boolean
   */
   public function addPerm($name, $perm)
   {
   }
   
   /**
   * delete() - Deletes area from table permissions
   *
   * @access public
   * @param Int $id
   * @return Boolean
   */
   public function delete($id)
   {   
   }

   /**
   * getPerms() - Gets the permissions of an user
   *
   * @access public
   * @param Int $userId
   * @return Boolean
   */
   public function getPerms($userId)
   {
   }

   /**
   * getPerm() - Gets the required permission of an area
   *
   * @access public
   * @param Int $name
   * @return Boolean
   */
   public function getPerm($id)
   {
   }

   /**
   * check() - Checks access rights
   *
   * @access public
   * @param Int $area
   * @param Int $perms
   * @return Boolean
   */
   public function check($id, $perms)
   {
      return ($area & $perms) == $perms) ? true : false;
   }
}
?>
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 613
Registriert: 09.12.2007, 20:12
Wohnort: Göttingen

Re: Binäres Rechtesystem

Beitragvon Guillermo am 20.07.2008, 11:44

Sehr sehr teil, ich denke sowas werde ich auch machen :P, danke für den Tipp, aber helfen kann ich dir nicht :)
Gebildet ist der, der weiß, wo er findet, was er nicht weiß.
Benutzeravatar
Guillermo
Mitglied
 
Beiträge: 486
Registriert: 01.10.2007, 18:18
Wohnort: Auerbach i.d.Opf

Re: Binäres Rechtesystem

Beitragvon Basti am 20.07.2008, 12:08

Schöne Idee, etwas ähnliches habe ich in meinem CMS auch bereits angewendet. Dort habe ich allerdings nicht mit einer Umwandlung zwischen Dezimal- und Binärzahlen gearbeitet, sondern einfach geprüft, ob die jeweilige Stelle mit einer 0 oder 1 besetzt ist, was letzten Endes aber ähnlich ist. Ich habe aber gerade gesehen, dass PHP mit decbin() und bindec() gleich zwei praktische Funktionen mitliefert, die die Umwandlung sehr leicht machen.
Dies wäre für mich eine Überlegung wert, da ich dann nicht mehr jede Stelle einzeln überprüfen muss, sondern einfach über die Summe gehen kann, mit der wie du ja bereits sagtest die jeweiligen Rechte eindeutig ermittelt werden können.

Der Aufbau deiner Klasse sieht bisher schon gut aus, vielleicht solltest du noch eine Methode zum Bearbeiten der Rechte einplanen, oder ist es so geplant, dass die alten Rechte beim Bearbeiten einfach entfernt werden und anschließend die neuen eingetragen werden?
Das wäre das einzige, was ich aktuell anzumerken hätte.
Benutzeravatar
Basti
Moderator
 
Beiträge: 1974
Registriert: 15.06.2006, 17:33
Wohnort: Rheinbreitbach

Re: Binäres Rechtesystem

Beitragvon Dac-XP am 20.07.2008, 13:28

Hi!

Ich habe bei meinem CMS zunächst auch an eine Rechteverwaltung in dieser Art gedacht, hielt es aber nicht für zweckmäßig.
Schließlich kann ich nicht jede Aktion in die drei Aktionen Lesen / Schreiben / Ausführen unterteilen. Wie erlaube ich einem Benutzer dann zum Beispiel sich als Administrator einzuloggen? Oder als anderes Beispiel habe ich die Benutzerverwaltung in drei Kategorien unterteilt (Anlegen, Löschen, Ändern), Einstellungen haben aber nur eine Kategorie (nämlich: Einstellungen vornehmen). In diesem Fall ist die Verwaltung mit dem binären System ja unsinnig.

Die Lösung, die ich verwende ist leider auch nicht sehr performant, weil jedes mal, wenn ich überprüfe, ob jemand über ein Recht verfügt mache ich eine MySQL-Abfrage über 5 Tabellen (Ich habe auch noch Benutzergruppen dazwischen geschaltet).
Benutzeravatar
Dac-XP
Mitglied
 
Beiträge: 1921
Registriert: 23.06.2005, 19:47
Wohnort: Mönchengladbach / NRW

Re: Binäres Rechtesystem

Beitragvon Avedo am 20.07.2008, 14:13

@Basti: Danke eine Methode update sollte ich wohl auch noch hinzufügen. Allerdings habe ich garnicht vor alle Zahlen in binären Code umzuwandeln. Dank der binären Operatoren, die PHP mit sich bringt, ist das auch nicht nötig. Ich denke ein kleines Beispiel würde da jetzt helfen...
Code: Alles auswählen
// permissions from database
$perm = 6;

if($perm >= 6)
{
   // writing allowed
}

if($perm == 1 || $perm == 3 || $perm == 7)
{
   // allowed to take orders
}

Das geht allerdings auch einfacher.
Code: Alles auswählen
if(($perm & 2) == 2)
{
   // writing allowed
}

if(($perm & 4) == 4)
{
   // reading allowed
}



Überlege nun ob ich die Klasse auf MySQLi oder MySQL aufbaue.

@Dac-XP: Man muss ja nicht immer die Rechte Schreiben, Lesen und Ausführen vergeben.
MfG, Andy
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 613
Registriert: 09.12.2007, 20:12
Wohnort: Göttingen

Re: Binäres Rechtesystem

Beitragvon Ingo am 20.07.2008, 15:02

Ehe sich unter zufällig lauschenden PHP-Neulingen Verwirrung breit macht, nur kurz eine Anmerkung
zur Terminologie: Binäre Operatoren - Bitoperatoren. In diesem Thred sind bisher Bitoperatoren gemeint.

Es gibt unäre, binäre und ternäre Operatoren. Unäre haben ein Argument, zum Beispiel das "-" als
Vorzeichen in "$a = -5;". Binäre Operatoren haben zwei Argumente, z.B. das "-" als Subtraktion
in "$a = $b - 5;" oder die Bit- und logischen Operatoren. Der ternäre Operator ?: hat drei Argumente:
"($x == 1) ? $a : $b".
Bitoperatoren wie & | verknüpfen Zahlen bitweise: dual 0110 | 0011 ergibt 0111. Weil die CPU
grundsätzlich nur mit Binärzahlen (Dualzahlen) arbeitet, erübrigt sich auch eine Umwandlung; auch wenn
das logisch verzwickt erscheinen mag. (Bei der Entwicklung einer Videostream-Reparatursoftware in C++,
wo man ständig Bits 'rumschubst, hatte mir diese Überlegung eine ganze Weile zu schaffen gemacht.)

Logische Operatoren wie && || sehen zwar ähnlich aus, verknüpfen aber die Argumente als Ganze
miteindander und nicht bitweise ("Welchen logischen Wert hat das ganze Argument? Verknüpfe diesen.").
Die beste Browserweiche ... sitzt zwischen den Ohren ;o]
Benutzeravatar
Ingo
Moderator
 
Beiträge: 724
Registriert: 01.04.2007, 23:21
Wohnort: Neuss/NRW

Re: Binäres Rechtesystem

Beitragvon Avedo am 21.07.2008, 14:08

Hallo!
Habe die Klasse im Prinzip fertig gestellt. Allerdings kann es gut sein, dass sie noch einige Fehler enthält, da sie leider gestern Nacht geschrieben wurde. Das ganze sollte aber weitest gehend stimmen. Getestet wurde sie noch nicht. Kleinere Änderungen werden bestimmt auch noch gemacht werden. Ich würde mich aber auf jeden Fall über Kommentare, Anregungen, aber auch Fragen freuen.
MfG, Andy
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 613
Registriert: 09.12.2007, 20:12
Wohnort: Göttingen

Re: Binäres Rechtesystem

Beitragvon Avedo am 22.07.2008, 02:24

Guten Morgen!
Ich habe noch etwas an der Klasse weiter gearbeitet und angefangen sie zu testen. Leider gibt es noch einige Probleme, bei denen ich noch nicht so richtig weiter komme.

Die Methode addPerm(), mit deren Hilfe man neue geschützte Bereiche hinzufügen können soll, funktioniert leider nicht so richtig. Das SQL-Query ist wohl fehlerhaft und ich kann leider nicht sagen, wo da mein Fehler liegt. Kann mir da jemand helfen?

Außerdem scheinen mir noch einige andere Queries wie bei userPerm() und getPerms() noch zu kompliziert zu sein. Kennt jemand eine Möglichkeit der Vereinfachung?

Des weiteren würde ich in den Methoden getPerm() und delPerm() gern optional entweder den Namen oder die Id der Section übergeben lassen. Hat jemand einen Vorschlag, wie ich das am besten lösen könnte?

Zu guter Letzt möchte ich noch die Methode editUser() und addUser() hinzufügen, die beide die Parameter $fields und $values (beides Arrays) übergeben bekommen sollen. Natürlich wird bei editUser() zusätzlich noch die User-Id mit übergeben. Mein Problem ist allerdings, wie ich bei editUser() diese beiden Arrays richtig in das Query einbinde, damit die Datenbank es auch annimmt. Vielleicht kann mir auch dabei jemand helfen.

Ich wäre euch sehr dankbar, wenn ihr mir den ein oder anderen Tipp oder weitere Anregungen geben könntet. Wäre auch sehr nett, wenn jemand mal über meine Queries schauen könnte. Mysql ist leider ein bisschen mein Stiefkind. :oops:
MfG, Andy

PS: Am Ende des Scriptes ist ein kleiner Testaufruf zu sehen.

Permissions.php
Code: Alles auswählen
<pre>
<?php 
error_reporting(E_ALL);

/***
* Permissions class allows handling access rights

* @package Permissions
* @version 0.2
* @author Andreas Wilhelm <Andreas2209@web.de>
* @copyright Andreas Wilhelm
**/ 
class Permissions
{
   // important class variables
   protected $db;   
   protected $userTab;
   protected $permTab;   
   
   /**
   * Cunstructor - Initiates important class variables
   *
   * @access public
   * @param Obj $db
   * @param Str $userTab
   * @param Str $permTab
   * @return NONE
   */
   public function __construct(mysqli $db, $userTab, $permTab)
   {
      // save parameters to class variables
      $this->db = $db;   
      $this->permTab = trim($permTab);
      $this->userTab = trim($userTab);
      
      // check if a permTab is given
      if( empty($this->permTab) )
      {
         throw new Exception("Invalid or no sql perm-table given.");
      }
      
      // check if a userTab is given
      if( empty($this->userTab) )
      {
         throw new Exception("Invalid or no sql user-able given.");
      }   
   }

   /**
   * addPerm() - Adds a new protected section
   *
   * @access public
   * @param Str $name
   * @return Boolean
   */
   public function addPerm($name)
   {
      // get maximum value
      $sql = "SELECT
            max(perm) AS perm
         FROM
            `{$this->permTab}`";
      
      // send sql-query
      $result = $this->db->query($sql);
      
      // check result
      if($this->db->affected_rows <= 0)
      {
         throw new Exception("Cannot get maximum perm-value.");
      }
      
      // save perms to string
      while ($row = $result->fetch_assoc())
      {
         $max = $row['perm'];
      }
      
      // calculate new perm-value
      $a = log($max, 2) + 1;
      $perms = 2^$a;
      
      // add new section
      $sql = "INSERT INTO {$this->permTab}
            (id, name, perm)
         VALUES
            ('', {$name}, {$perms})";
      
      // send sql-query
      $this->db->query($sql);
      
      // check result
      if($this->db->affected_rows <= 0)
      {
         throw new Exception("Cannot create protected section {$name}.");
      }

      return true;
   }
   
   /**
   * delPerm() - Deletes section from permissions-table
   *
   * @access public
   * @param Int $id
   * @return Boolean
   */
   public function delPerm($id)
   {   
      // delete section
      $sql = "DELETE
         FROM
            `{$this->permTab}`
         WHERE
            {$id}";
      
      // send sql-query               
      $this->db->query($sql);
      
      // check result
      if($this->db->affected_rows <= 0)
      {
         throw new Exception("Cannot delete {$name}.");
      }
      
      return true;
   }

   /**
   * getPerm() - Gets the required permission of an section
   *
   * @access public
   * @param Int $id
   * @return String
   */
   public function getPerm($id)
   {
      // get permissions
      $sql = "SELECT `perm`
         FROM
            `{$this->permTab}`
         WHERE
            `id` = {$id}";
      
      // send sql-query               
      $result = $this->db->query($sql);
      
      // check result
      if(!$result)
      {
         throw new Exception("Cannot get permissions of section {$id}.");
      }
      
      // save perms to string
      while ($row = $result->fetch_assoc())
      {
         $perms = $row['perm'];
      }      
      
      return $perms;
   }

   /**
   * getPerms() - Gets the required permission of an section
   *
   * @access public
   * @return Array
   */
   public function getPerms()
   {
      // get permissions
      $sql = "SELECT *
         FROM
            `{$this->permTab}`";
      
      // send sql-query               
      if( $result = $this->db->query($sql) )
      {
         // initiate variable $perms
         $perms = array();
         
         // save perms to associative array
         while ($row = $result->fetch_assoc())
         {
            $perms[] = $row;
         }

         /* free result set */
         $result->close();
      }
      
      else
      {
         throw new Exception("Cannot get permissions of section {$name}.");
      }
      
      return $perms;
   }

   /**
   * userPerm() - Gets the permissions of an user
   *
   * @access public
   * @param Int $userId
   * @return Integer
   */
   public function userPerm($userId)
   {
      // get permissions
      $sql = "SELECT `perm`
         FROM
            `{$this->userTab}`
         WHERE
            `id` = {$userId}";
      
      // send sql-query               
      $result = $this->db->query($sql);
      
      // check result
      if(!$result)
      {
         throw new Exception("Cannot get permissions of user {$userId}.");
      }
      
      // fetch object of result
      $obj = $result->fetch_object();
      
      // save perms to string
      $perms = $obj->perm;
      
      return $perms;
   }

   /**
   * addUser() - Updates the permissions of an user
   *
   * @access public
   * @param Arr $fields
   * @param Arr $values
   * @return Boolean
   */
   public function addUser($fields = array(), $values = array())
   {
   
      if(count($fields) == count($values))
      {
         $fields = !empty($fields) ? '`' . implode('`, `', $fields) . '`' : '';
         $values = !empty($values) ? '"' . implode('", "', $values) . '"' : '';
      }
      
      else
      {
         throw new Exception("Field count does not match value count");   
      }
      
      $sql = "INSERT INTO `{$this->userTab}`
         SET
            (`id`, {$fields})
         VALUES
            (``, {$values})";
      
      // check result
      if( $this->db->affected_rows <= 0 )
      {
         throw new Exception("Cannot create user.");
      }
      
      return true;
   }

   /**
   * editUser() - Edits all values of an user
   *
   * @access public
   * @param Int $userId
   * @param Arr $fields
   * @param Arr $values
   * @return Boolean
   */
   public function editUser($userId, $fields = array(), $values = array())
   {
   }

   /**
   * check() - Checks access rights
   *
   * @access public
   * @param Int $perm
   * @param Int $perms
   * @return Boolean
   */
   public function check($perm, $perms)
   {
      return (($perm & $perms) == $perms) ? true : false;
   }
}

try
{
   @$db = new mysqli("localhost", "web193", "andy1729", "usr_web193_2");

   $perm = new Permissions($db, "user", "permissions");
   
   if( !$perm->check(13, 4) )
   {
      echo 'Du kommst hier net rein! (13)<br />';
   }
   
   else
   {
      echo 'Welcome!<br />';
   }
   
   echo 'Der admin hat die Rechte '.$perm->userPerm(1).'.<br />';   
   echo 'Settings erfordert die Rechte '.$perm->getPerm(1).'.<br />';
   $perm->addPerm("user");
   print_r( $perm->getPerms() );
   $perm->addPerm("nicolaus");
   print_r( $perm->getPerms() );
   $perm->delPerm(2);
   print_r( $perm->getPerms() );
   $perm->addPerm("commissaries");
   print_r( $perm->getPerms() );
   
   if( !$perm->check(1, 4) )
   {
      echo 'Du kommst hier net rein! (1)<br />';
   }
   
   else
   {
      echo 'Welcome!<br />';
   }
}

catch(Exception $e)
{
   echo '<b>'.$e->getLine().': </b>'.$e->getMessage().'<br />';
}
?>
</pre>
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 613
Registriert: 09.12.2007, 20:12
Wohnort: Göttingen

Re: Binäres Rechtesystem

Beitragvon Avedo am 11.08.2008, 23:23

Guten Abend!
Ich habe das komplette System nochmals überarbeitet und optimiert. leider funktioniert das gnaze noch nicht wirklich und daher möchte ich euch zunächst das neue System vorstellen und euch dann um Hilfe bitten.

Wie schon zuvor soll es zwei Tabellen, eine für die User-Daten und eine für die Daten der "privaten" Bereiche geben. Die User-Tabelle enthält also im einfachsten Fall id | name | password | permissions. Die Tabelle für die "priavten" oder einfacher gesagt, für die geschützten Bereiche, enthält allerdings nun nur noch den Namen des Bereichs und eine zugehörige ID.

Wie findet man allerdings nun mit dem binären Wert aus der Permissions-Spalte der User Tabelle heraus, ob ein Benutzer zugriff auf einen bestimmten Bereich hat oder nicht? Oder auf welche Bereiche er überhaupt zugriff hat? Die Lösung ist eigentlich einfach. Nimmt man die ID für einen bestimmten bereich in zum Beispiel einem CM-System und nutzt diesen als Exponent zur Basis zwei, so erhält man den binären Wert, den der User als Teil seines binären Wertes besitzen muss.

Möchte man nun also alle IDs der Bereiche herausfinden, zu denen ein User Zugriff besitz, kann man dies relativ einfach auszählen. Ein Beispiel:

Es gibt die Bereiche bla(ID 1), lol(ID 2), omg(ID 3) und nop(ID 4).
Möchte nun jemand zum Beispiel den benötigten Binärwert zu bla wissen, muss er nur 2^ID(lol) = 2^2 = 4 rechnen.
Möchte man also alle Bereiche wissen, zu denen ein Benutzer Zugriff besitzt, muss man einfach nur nach dem größten möglichen Exponenten zur Basis zwei suchen, bei dessen Subtraktion vom binären Permissions-Wert des Users nicht null herauskommt. Man durchläuft also eine Schleife solange, bis kein Restwert der Permissions mehr da ist. Gibt es also einen Nutzer Klaus mit dem binären Permissions-Wert 20 in meinem oben begonnenen pseudo CM-System, so setzen sich seine Werte wie folgt zusammen.
P(Klaus) = 2^ID(nop) + 2^ID(lol)
Der Benutzer Klaus hat also Zugriff auf die Bereiche nop und lol.

In PHP kann man dies, wie schon gesagt mit einer Schleife leicht errechnen.
Code: Alles auswählen
// permissions of Klaus
$perms = 20;

//start counter
$i = 0;

// initiate array of ids
$mods = array();

// extrahate specific permissions
do
{
    if( (($p-pow(2,$i)) < 0) )
    {
        $e = $i-1;
        $p = $p-pow(2,$e);
        $mods[] = $e;
        $i = 0;
    }

    else
    {
        $i++;
    }
}
while( (($p-pow(2,$i)) < 0)  && ($p > 0) )

Nach Durchlaufen der Schleife enthält das Array $mods alle IDs zu den geschützten bereichen zu denen Klaus Zutritt besitzt, also 2 und 4.

Ich hoffe, dass das neue System klar geworden ist. Bei Fragen stehe ich natürlich gerne zur Verfügung und für Anregungen bin ich auch immer offen.

Doch, wie schon gesagt, funktioniert die umgeschriebene Klasse noch nicht ganz. Es tritt folgender Fehler auf und ich finde ihn einfach nicht, wodurch ich die Klasse auch noch nicht testen konnte.

Code: Alles auswählen
Parse error: syntax error, unexpected T_RETURN, expecting ';' in /home/www/web193/html/permissions.php on line 180


Ich hoffe mir kann jemand helfen. Ich wäre sehr dankbar. Die betreffende Zeile ist übrigens die mit der while()-Schleife in der getPerms()-Methode.
MfG, Andy

Übersicht über die Methoden
__construct() - Setzt die wichtigen Variablen
addMod() - Fügt einen geschützten Bereich hinzu
delMod() - Entfernt einen geschützten Bereich
getMods() - Gibt die IDs aller geschützter bereiche zurück
getPerms() - Gibt die IDs zu den Bereichen zu denen ein Benutzer Zutritt besitzt zurück
addUser() - Fügt einen Benutzer hinzu
check() - Überprüft die Zutritts-Berechtigung eines Nutzers
getId() - Gibt die ID zu einem Bereich oder einem Nutzer anhand der ID oder des Namens zurück

Permissions.php
Code: Alles auswählen
<pre>
<?php
error_reporting(E_ALL);

/***
* The Permissions class allows reading and editting access rights
*
* @package Permissions
* @version 0.3
* @author Andreas Wilhelm <Andreas2209@web.de>
* @copyright Andreas Wilhelm
**/
class Permissions
{
    // private class variables
    private $db;
    private $userTab;
    private $modTab;

    /**
    * Constructor - Is called when the class is instanced
    *
    * @access public
    * @param Obj $db
    * @param Str $userTab
    * @param Str $modTab
    * @return NONE
    */
    public function __construct(mysqli $db, $userTab, $modTab)
    {
        // save parameters to class variables
        $this->db = $db;
        $this->modTab = trim($modTab);
        $this->userTab = trim($userTab);
    }

    /**
    * addMod() - Adds a new protected section
    *
    * @access public
    * @param Str $name
    * @return Boolean
    */
    public function addMod($name)
    {
        // add new section
        $sql = "INSERT INTO {$this->modTab}
                (`id`, `name`)
            VALUES
                ('', '{$name}')";

        // send sql-query
        $this->db->query($sql);

        // check result
        if($this->db->affected_rows <= 0)
        {
            throw new Exception("Cannot create section {$name}.");
        }

        return true;
    }

    /**
    * delMod() - Deletes section from table
    *
    * @access public
    * @param Mix $ident
    * @return Boolean
    */
    public function delMod($ident)
    {
        // get id of the section
        $id = $this->getId($ident, $this->modTab);
       
        // delete section
        $sql = "DELETE
            FROM
                {$this->modTab}
            WHERE
                'id' = '{$id}'";

        // send sql-query
        $this->db->query($sql);

        // check result
        if($this->db->affected_rows <= 0)
        {
            throw new Exception("Cannot delete {$id}.");
        }

        return true;
    }

    /**
    * getMods() - Returns all section-ids
    *
    * @access public
    * @return Array
    */
    public function getMods()
    {
        // get section-ids
        $sql = "SELECT
            *
         FROM
                {$this->modTab}";

        // send sql-query
        $result = $this->db->query($sql);

        // check result
        if(!$result)
        {
            throw new Exception("Cannot get sections.");
        }
       
        // save perms to array
      $mods = array();
      $i=0;
      while( $row = $result->fetch_assoc() )
      {
         $mods[$i]['id'] = $row['id'];
         $mods[$i]['name'] = $row['name'];
         $i++;
      }

        return $mods;
    }

    /**
    * getPerms() - Returns all rights of an user
    *
    * @access public
    * @param Mix $ident
    * @return Array
    */
    public function getPerms($ident)
    {
        // get id of the user
        $id = $this->getId($ident, $this->userTab);

        // get permissions of the user
        $sql = "SELECT
                `perm`
            FROM
                {$this->userTab}
            WHERE
                'id' = '{$id}'";

        // send query
        $result = $this->db->query($sql);

        // check result
        if(!$result)
        {
            throw new Exception("Cannot get permissions of user {$userId}.");
        }

        // save perms to array
        $user = $result->fetch_assoc();

        // save perms to integer
        $p = $user['perm'];

        //start counter
        $i = 0;

        // initiate array of ids
        $mods = array();

        // extrahate specific permissions
        do
        {
            if( (($p-pow(2,$i)) < 0) )
            {
                $e = $i-1;
                $p = $p-pow(2,$e);
                $mods[] = $e;
                $i = 0;
            }

            else
            {
                $i++;
            }
        }
        while( (($p-pow(2,$i)) < 0)  && ($p > 0) );

        return $mods;
    }

    /**
    * addUser() - Updates the permissions of an user
    *
    * @access public
    * @param Arr $fields
    * @param Arr $values
    * @return Boolean
    */
    public function addUser($fields = array(), $values = array())
    {
        if(count($fields) == count($values))
        {
            $fields = !empty($fields) ? '`' . implode('`, `', $fields) . '`' : '';
            $values = !empty($values) ? '\'' . implode('\', \'', $values) . '\'' : '';
        }

        else
        {
            throw new Exception("Field count does not match value count");
        }

        $sql = "INSERT INTO {$this->userTab}
                (`id`, {$fields})
            VALUES
                ('', {$values})";

        // check result
        if( $this->db->affected_rows <= 0 )
        {
            throw new Exception("Cannot create user.");
        }

        return true;
    }

    /**
    * check() - Checks access rights
    *
    * @access public
    * @param Mix $ident
    * @param Int $perms
    * @return Boolean
    */
    public function check($ident, $perms)
    {
        // get id of the section
        $id = $this->getId($ident, $this->modTab);

        // create section perms
        $perm = pow(2, $id);

        return (($perm & $perms) == $perms) ? true : false;
    }

    /**
    * getId() - Returns the id of an user
    *
    * @access private
    * @param Mix $ident
    * @param Str $table
    * @return Integer
    */
    private function getId($ident, $table)
    {
        // check if identifier is an integer
        if( is_numeric($ident) )
        {
            $id = $ident;
        }

        else
        {
            // get user-id
            $sql = "SELECT `id`
                FROM
                    {$table}
                WHERE
                    'name' = '{$ident}'";

            // send sql-query
            $result = $this->db->query($sql);

            // check result
            if(!$result)
            {
                throw new Exception("Cannot get user-id of {$ident}.");
            }
       
            // save user-values to array
         $user = array();
         while( $row = $result->fetch_assoc() )
         {
            $user[] = $row['id'];
         }

            // save id to integer
            (int) $id = $user[0];
        }

        return $id;
    }
}

try
{
   // create connection to database
    @$db = new mysqli("localhost", "user", "pwd", "usr_db");

   // instance permissions class
    $perm = new Permissions($db, "user", "permissions");
   
    // show status quo
    echo "Status Quo.\n";
    print_r( $perm->getMods() );

   // add area "user"
    echo "Add section user.\n";
    $perm->addMod("user");
    print_r( $perm->getMods() );
   
    // add area "nicolaus"
    echo "Add section nicolaus.\n";
    $perm->addMod("nicolaus");
    print_r( $perm->getMods() );
   
    // remove area "nicolaus"
    echo "Remove section nicolaus.\n";
    $perm->delMod("nicolaus");
    print_r( $perm->getMods() );
   
    // print out rights of user "avedo"
    echo "Avedo has the following rights:\n";
    print_r( $perm->getPerms() );
   
    // print out rights of user "klaus"
    echo "Klaus has the following rights:\n";
    print_r( $perm->getPerms() );
}

catch(Exception $e)
{
    echo "Error:<br />";
    echo "<b>" . $e->getLine() . "</b>" . ": " . $e->getMessage() . "<br />";
}
?>
Zuletzt geändert von Avedo am 22.08.2008, 03:16, insgesamt 2-mal geändert.
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 613
Registriert: 09.12.2007, 20:12
Wohnort: Göttingen

Re: Binäres Rechtesystem

Beitragvon Ingo am 12.08.2008, 02:56

Hi.

Der Syntaxfehler ist schnell behoben: es fehlt das Semikolon hinter do {...} while(...);
unmittelbar vor Zeile 180. - Auf die Exponentialmethode werde ich einen näheren Blick
werfen, soweit ich etwas mehr Luft habe.

Gruß, Ingo :)
Die beste Browserweiche ... sitzt zwischen den Ohren ;o]
Benutzeravatar
Ingo
Moderator
 
Beiträge: 724
Registriert: 01.04.2007, 23:21
Wohnort: Neuss/NRW

Re: Binäres Rechtesystem

Beitragvon Avedo am 12.08.2008, 12:31

Danke für den Tipp. Den Fehler hätte ich in den nächsten Stunden wohl nicht gefunden. So konnte ich nun wenigstens das Script testen, auch wenn es noch nicht wirklich funktioniert. Und zwar Funktioniert das Löschen eines Bereichs via delMod() noch nicht und die IDs aller Bereiche können auch noch nicht via getMods() zurückgegeben werden. Die Methode gibt zwar die erste ID korrekt zurück, aber nur die erste, obwohl sie, wie im Testaufruf am Ende des Scripts zu sehen ist, später noch weitere IDs von neuen Bereichen ausgeben soll. Ich vermute mal stark, dass mein Problem bei den Queries liegt, kann dies aber nicht mit Sicherheit sagen. Kann mir da noch jemand weiterhelfen?
MfG, Andy
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 613
Registriert: 09.12.2007, 20:12
Wohnort: Göttingen

Re: Binäres Rechtesystem

Beitragvon Avedo am 16.08.2008, 12:51

Kann mir keiner einen kleinen Tipp geben oder eine Alternative eröffnen? Die Klasse macht mich langsam fertig. Da war die Arbeit mit den ganzen RFCs doch viel leichter. Ich konnte bisher zumindest den Fehler in der Methode getMods() beheben und habe zudem festgestellt, dass der Fehler in delMod() wahrscheinlich nicht in dieser Methode sondern in der Methode getId() liegt, wobei ich nicht weiß, was daran falsch ist. Zudem gibt es noch große Probleme mit den Methoden zur Benutzer-Verwaltung. Die Methoden getPerms() und addUser() funktionieren leider auch noch nicht. Bei der Methode addUser() liegt das wahrscheinlich an dem implode, dass dort die User-Daten in ein Query einbinden soll. Bei der Methode getPerms() liegt der Fehler wahrscheinlich auch in der Methode getId(). Keiner eine Idee? Ich bin am verzweifeln.
MfG, Andy
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 613
Registriert: 09.12.2007, 20:12
Wohnort: Göttingen

Re: Binäres Rechtesystem

Beitragvon Avedo am 22.08.2008, 02:43

Hallo!
Also erstes möchte ich mich für das mehrfach Posting und das freudengeladene Blabla, das nun folgen wird, entschuldigen. Des weiteren möchte ich mich bei den fleißigen Helfern nochmals bedanken. Die Klasse ist nun (in ihrem jetzigen Status) fehlerfrei. Nun ist natürlich die Frage, ob das alles so ausreichend ist. Darum würde mich nun interessieren, welche Methoden ihr in einer Klasse zur Rechte und Benutzerverwaltung noch missen würdet. Die folgenden Methoden sind bisher implementiert worden.

Übersicht über die Methoden
__construct() - Setzt die wichtigen Variablen
addMod() - Fügt einen geschützten Bereich hinzu
delMod() - Entfernt einen geschützten Bereich
getMods() - Gibt die Daten aller geschützter Bereiche zurück (Id, Name)
getPerms() - Gibt die IDs zu den Bereichen zu denen ein Benutzer Zutritt besitzt zurück
addUser() - Fügt einen Benutzer hinzu
check() - Überprüft die Zutritts-Berechtigung eines Nutzers
getId() - Gibt die ID zu einem Bereich oder einem Nutzer anhand der ID oder des Namens zurück

Die Letzte Methode erscheint auf den ersten Blick sehr unsinnig, ist aber sehr praktisch. Sie ermöglicht es, dass man zum Beispiel beim Aufruf der Methode check entweder den Namen oder die Id eines Nutzers übergeben kann und dass man den Namen oder die Id eines geschützten Bereichs übergeben kann. So wird dem Nutzer die Arbeit erleichtert.

Ich würde mich also über Rückmeldungen und vorallem Anregungen freuen.
MfG, Andy
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 613
Registriert: 09.12.2007, 20:12
Wohnort: Göttingen

Re: Binäres Rechtesystem

Beitragvon Manuel am 22.08.2008, 02:58

Hi Avedo!

Ich hatte leider bisher nicht die Zeit, mir die Klasse anzuschauen, aber was du da machst schaut echt klasse aus. Nur das Wort "fehlerfrei" würde ich niemals in Verbindung mit jeglichem Quellcode bringen... ;)

Lg,
Manuel ;-]
Benutzeravatar
Manuel
Site Admin
 
Beiträge: 9114
Registriert: 10.12.2004, 19:29
Wohnort: Asbach

Re: Binäres Rechtesystem

Beitragvon Avedo am 22.08.2008, 03:08

Mit dem Fehlerfrei hast du wahrscheinlich recht. :lol: Allerdings hat er alle meine Tests überstanden. Und darauf habe ich nun für 8 oder 9 Methoden 3 Stunden verwendet. Ich hoffe einfach mal, dass das reicht!. error_reporting(E_ALL), print_r() und <pre></pre> haben mir dabei gute Dienste geleistet. :lol:
MfG, Andy

//EDIT: Habe nochmal den neuen Quellcode angehängt. Wäre im übrigen super, wenn ihr *.php, *.html und *.css Anhänge bis 20kb mal freischalten würdet.

Code: Alles auswählen
<pre>
<?php
error_reporting(E_ALL);

/***
* Class Permissions
*
* The Permissions class enables the easy management
* of access rights an user data. Reading and editting
* access rights to secured areas and the creation
* of such secured areas is one part of this class.
* On the other hand this class accounts for the
* creation and editting of user data.
*
* @package Permissions
* @version 0.4
* @author Andreas Wilhelm <Andreas2209@web.de>
* @copyright Andreas Wilhelm
**/
class Permissions
{
    // private class variables
    private $db;
    private $userTab;
    private $modTab;

    /**
    * Constructor - Is called when the class is instanced
    *
    * @access public
    * @param Obj $db
    * @param Str $userTab
    * @param Str $modTab
    * @return NONE
    */
    public function __construct(mysqli $db, $userTab, $modTab)
    {
        // save parameters to class variables
        $this->db = $db;
        $this->modTab = trim($modTab);
        $this->userTab = trim($userTab);
    }

    /**
    * addMod() - Adds a new protected section
    *
    * @access public
    * @param Str $name
    * @return Boolean
    */
    public function addMod($name)
    {
        // add new section
        $sql = "INSERT INTO {$this->modTab}
                (`id`, `name`)
            VALUES
                ('', '{$name}')";

        // send sql-query
        $this->db->query($sql);

        // check result
        if($this->db->affected_rows <= 0)
        {
            throw new Exception("Cannot create section {$name}.");
        }

        return true;
    }

    /**
    * delMod() - Removes section from table
    *
    * @access public
    * @param Mix $ident
    * @return Boolean
    */
    public function delMod($ident)
    {
        // get id of the section
        $id = $this->getId($ident, $this->modTab);
       
        // delete section
        $sql = "DELETE
            FROM
                {$this->modTab}
            WHERE
                id = '{$id}'";

        // send sql-query
        $this->db->query($sql);

        // check result
        if($this->db->affected_rows <= 0)
        {
            throw new Exception("Cannot delete {$id}.");
        }

        return true;
    }

    /**
    * getMods() - Returns all section-ids
    *
    * @access public
    * @return Array
    */
    public function getMods()
    {
        // get section-ids
        $sql = "SELECT
            *
         FROM
                {$this->modTab}";

        // send sql-query
        $result = $this->db->query($sql);

        // check result
        if(!$result)
        {
            throw new Exception("Cannot get sections.");
        }
       
        // save perms to array
      $mods = array();
      $i=0;
      while( $row = $result->fetch_assoc() )
      {
         $mods[$i]['id'] = $row['id'];
         $mods[$i]['name'] = $row['name'];
         $i++;
      }

        return $mods;
    }

    /**
    * getPerms() - Returns all rights of an user
    *
    * @access public
    * @param Mix $ident
    * @return Array
    */
    public function getPerms($ident)
    {
        // get id of the user
        $id = $this->getId($ident, $this->userTab);

        // get permissions of the user
        $sql = "SELECT
                `perm`
            FROM
                {$this->userTab}
            WHERE
                id = '{$id}'
            LIMIT 1";
      
        // send sql-query
        if ( $result = $this->db->query($sql) )
        {
         // save result into an array
         $array = $result->fetch_array();
            
         // get perm from array
         $perm = $array['perm'];
        }
      
        else
        {
            throw new Exception("Cannot get permissions of user {$userId}.");
        }

        //start counter
        $i = 0;

        // initiate array of ids
        $mods = array();

        // extrahate specific permissions
        do
        {
            if( ($perm - pow(2,$i)) < 0 )
            {
                $e = $i-1;
                $perm = $perm - pow(2,$e);
                array_push($mods, $e);
                $i = 0;
            }

            else
            {
                $i++;
            }
        }
        while( $perm > 0 );

        return $mods;
    }

    /**
    * addUser() - Updates the permissions of an user
    *
    * @access public
    * @param Arr $fields
    * @param Arr $values
    * @return NONE
    */
    public function addUser($fields = array(), $values = array())
    {
        // check count of fields and values
        if( count($fields) == count($values) )
        {
            $fields = !empty($fields) ? '`' . implode('`, `', $fields) . '`' : '';
            $values = !empty($values) ? '\'' . implode('\', \'', $values) . '\'' : '';
        }

        else
        {
            throw new Exception("Invalid user data.");
        }
      
      // create an new user
        $sql = "INSERT INTO {$this->userTab}
                (`id`, {$fields})
            VALUES
                ('', {$values})";

        // send query
        $this->db->query($sql);

        // check result
        if( $this->db->affected_rows <= 0 )
        {
            throw new Exception("Cannot create user.");
        }
    }

    /**
    * check() - Checks access rights
    *
    * @access public
    * @param Mix $user
    * @param Mix $mod
    * @return Boolean
    */
    public function check($user, $mod)
    {
        // get id of the user
        $userId = $this->getId($user, $this->userTab);

        // get permissions of the user
        $sql = "SELECT
                `perm`
            FROM
                {$this->userTab}
            WHERE
                id = '{$userId}'
            LIMIT 1";
      
        // send sql-query
        if ( $result = $this->db->query($sql) )
        {
         // save result into an array
         $array = $result->fetch_array();
            
         // get perm from array
         $perms = $array['perm'];
        }
      
        else
        {
            throw new Exception("Cannot get permissions of user {$userId}.");
        }
       
        // get id of the section
        $modId = $this->getId($mod, $this->modTab);

        // create section perms
        $needed = pow(2, $modId);

        return (($perms & $needed) == $needed) ? true : false;
    }

    /**
    * getId() - Returns the id to a user or secured area
    *
    * @access private
    * @param Mix $ident
    * @param Str $table
    * @return Integer
    */
    private function getId($ident, $table)
    {
        // check if identifier is an integer
        if( is_numeric($ident) )
        {
            $id = $ident;
        }

        else
        {         
            // get id
         $sql = "SELECT
               `id`
            FROM
               {$table}
            WHERE
               name = '{$ident}'
            LIMIT 1";
      
            // send sql-query
         if ( $result = $this->db->query($sql) )
         {
            // save result into an array
            $array = $result->fetch_array();
            
            // get id from array
            $id = $array['id'];
         }
      
         else
         {
            return false;
         }
        }

        return $id;
    }
}

try
{
   // create connection to database
    @$db = new mysqli("localhost", "user", "pwd", "db");

   // instance permissions class
    $perm = new Permissions($db, "user", "permissions");
   
    // show status quo
    echo "<b>Status Quo.</b>\n";
    print_r( $perm->getMods() );
    echo "\n\n";

   // add area "user"
    echo "<b>Add section user.</b>\n";
    $perm->addMod("user");
    print_r( $perm->getMods() );
    echo "\n\n";
   
    // add area "nicolaus"
    echo "<b>Add section nicolaus.</b>\n";
    $perm->addMod("nicolaus");
    print_r( $perm->getMods() );
    echo "\n\n";
   
    // add user peter
    echo "<b>Add user peter.</b>\n";
    $fields = array('name', 'password', 'email', 'perm');
    $values = array('peter', md5('gehweg'), 'peter@avedo.net', 10);
    $perm->addUser($fields, $values);
    echo "\n\n";
   
    // print out rights of user "avedo"
    echo "<b>Avedo has the following rights:</b>\n";
    print_r( $perm->getPerms(1) );
    echo "\n\n";
   
    // print out rights of user "klaus"
    echo "<b>Klaus has the following rights:</b>\n";
    print_r( $perm->getPerms('klaus') );
    echo "\n\n";
   
    // check if avedo has access to nicolaus
    if( $perm->check('avedo', 'nicolaus') )
    {
      echo "Avedo darf rein!\n";
    }
   
    else
    {
      echo "Avedo muss draussen bleiben!\n";
    }
   
    // check if klaus has access to nicolaus
    if( $perm->check('klaus', 'nicolaus') )
    {
      echo "Klaus darf rein!\n";
    }
   
    else
    {
      echo "Klaus muss draussen bleiben!\n";
    }
   
    // remove area "nicolaus"
    echo "<b>Remove section nicolaus.</b>\n";
    $perm->delMod("nicolaus");
    print_r( $perm->getMods() );
}

catch(Exception $e)
{
    echo "Error:<br />";
    echo "<b>" . $e->getLine() . "</b>" . ": " . $e->getMessage() . "<br />";
}
?>


Und die SQL-Datei zum testen, damit ihr nicht so viel Stress habt.
Code: Alles auswählen
CREATE TABLE `permissions` (
  `id` tinyint(4) NOT NULL auto_increment,
  `name` varchar(30) NOT NULL default '',
  PRIMARY KEY  (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0;

INSERT INTO `permissions` VALUES (1, 'settings');
INSERT INTO `permissions` VALUES (2, 'articles');

CREATE TABLE `user` (
  `id` tinyint(4) NOT NULL auto_increment,
  `name` varchar(20) NOT NULL default '',
  `password` varchar(32) NOT NULL default '',
  `email` varchar(60) NOT NULL default '',
  `perm` tinyint(3) unsigned NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0;

INSERT INTO `user` VALUES (1, 'avedo', 'ddd6acc47c23379394ee7cdcbb4ea22b', 'andreas2209@web.de', 30);
INSERT INTO `user` VALUES (2, 'klaus', '0f5f53ea8fe0e8eeb72db72b47ddf351', 'klaus@avedo.net', 14);       
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 613
Registriert: 09.12.2007, 20:12
Wohnort: Göttingen


Zurück zu PHP

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast