Frage

Bits und Bitmaske sind etwas, das ich schon seit einiger Zeit zu verstehen habe, aber ich möchte lernen, wie man sie für Einstellungen und ähnliches in PHP verwendet.

Ich habe endlich eine Klasse gefunden, die behauptet, genau das zu tun, und wie ich beurteilen kann, scheint es zu funktionieren, aber ich bin nicht sicher, ob es der beste Weg ist, dies zu tun. Ich werde die Klassendatei mit Beispielcode unten veröffentlichen, um sie in funktionierender Reihenfolge anzuzeigen.

Bitte, wenn Sie Erfahrung haben, sagen Sie mir, ob es für Leistung oder irgendetwas anderes verbessert werden kann. Ich möchte das wirklich lernen und ich habe es gelesen, aber es ist schwierig für mich, bisher zu verstehen.

Die Klasse...

<?php
    class bitmask
    {
        /**
         * This array is used to represent the users permission in usable format.
         *
         * You can change remove or add valuesto suit your needs.
         * Just ensure that each element defaults to false. Once you have started storing
         * users permsisions a change to the order of this array will cause the
         * permissions to be incorectly interpreted.
         *
         * @type Associtive array
         */
        public $permissions = array(
                                    "read" => false,
                                    "write" => false,
                                    "delete" => false,
                                    "change_permissions" => false,
                                    "admin" => false
                                    );

        /**
         * This function will use an integer bitmask (as created by toBitmask())
         * to populate the class vaiable
         * $this->permissions with the users permissions as boolean values.
         * @param int $bitmask an integer representation of the users permisions.
         * This integer is created by toBitmask();
         *
         * @return an associatve array with the users permissions.
         */
        public function getPermissions($bitMask = 0)
        {
            $i = 0;
            foreach ($this->permissions as $key => $value)
            {
                $this->permissions[$key] = (($bitMask & pow(2, $i)) != 0) ? true : false;

                // Uncomment the next line if you would like to see what is happening.
                //echo $key . " i= ".strval($i)." power=" . strval(pow(2,$i)). "bitwise & = " . strval($bitMask & pow(2,$i))."<br>";
                $i++;
            }
            return $this->permissions;
        }

        /**
         * This function will create and return and integer bitmask based on the permission values set in
         * the class variable $permissions. To use you would want to set the fields in $permissions to true for the permissions you want to grant.
         * Then call toBitmask() and store the integer value.  Later you can pass that integer into getPermissions() to convert it back to an assoicative
         * array.
         *
         * @return int an integer bitmask represeting the users permission set.
         */
        function toBitmask()
        {
            $bitmask = 0;
            $i = 0;
            foreach ($this->permissions as $key => $value)
            {

                if ($value)
                {
                    $bitmask += pow(2, $i);
                }
                $i++;
            }
            return $bitmask;
        }
    }
?>

Wie setze/speichere ich die Berechtigungen als Bitmask -Wert?

<?php
    /**
     * Example usage
     * initiate new bitmask object
     */
    $perms = new bitmask();

    /**
     * How to set permissions for a user
     */
    $perms->permissions["read"] = true;
    $perms->permissions["write"] = true;
    $perms->permissions["delete"] = true;
    $perms->permissions["change_permissions"] = true;
    $perms->permissions["admin"] = false;

    // Converts to bitmask value to store in database or wherever
    $bitmask = $perms->toBitmask();  //in this example it is 15
    $sql = "insert into user_permissions (userid,permission) values(1,$bitmask)";
    echo $sql; //you would then execute code to insert your sql.
?>

Beispiel für die Einnahme des Bitmask -Werts und die Rückgabe eines True/False für jedes Array -Element basierend auf dem Bitwert ....

<?php
    /**
     * Example usage to get the bitmask value from database or session/cache.... then put it to use.
     * $permarr returns an array with true/false for each array value based on the bit value
     */
    $permarr = $perms->getPermissions($bitmask);

    if ($permarr["read"])
    {
        echo 'user can read: <font color="green">TRUE</font>';
    }
    else {
        echo 'user can read: <font color="red">FALSE</font>';
    }

    //user can WRITE permission
    if ($permarr["write"])
    {
        echo '<br>user can write: <font color="green">TRUE</font>';
    }
    else {
        echo '<br>user can write: <font color="red">FALSE</font>';
    }
?>
War es hilfreich?

Lösung

Bitfelder sind ein sehr praktisches und effizientes Werkzeug für den Umgang mit Flags oder einer Reihe von Booleschen Werten im Allgemeinen.

Um sie zu verstehen, müssen Sie zuerst wissen, wie binäre Zahlen funktionieren. Danach sollten Sie sich die manuellen Einträge ansehen Bitgewise -Operatoren Und stellen Sie sicher, dass Sie wissen, wie eine bitweise und oder und linke/rechte Schicht funktioniert.

Ein bisschen Feld ist nichts anderes als ein ganzzahliger Wert. Nehmen wir an, die Größe unseres Bitfeldes ist fest und nur ein Byte. Computer arbeiten mit Binärzahlen. Wenn der Wert unserer Zahl also ist 29, Sie werden tatsächlich finden 0001 1101 in der Erinnerung.

Verwenden von bitweise und (&) und bitweise oder ((|) Sie können jedes Bit der Nummer einzeln aussagen und festlegen. Beide nehmen zwei Ganzzahlen als Eingabe ein und führen ein und/oder jedes Bit einzeln aus.

Um das erste Stück Ihrer Nummer vorzulesen, könnten Sie so etwas tun:

  0001 1101 (=29, our number)
& 0000 0001 (=1, bit mask)
= 0000 0001 (=1, result)

Wie Sie sehen, benötigen Sie eine Sonderzahl, bei der nur das Bit, an dem wir interessiert sind, eingestellt ist, das ist die sogenannte "Bitmaske". In unserem Fall ist es 1. Um das zweite Stück vorzulesen, müssen wir die in der Bitmaske in einer Ziffer links "schieben". Wir können das mit dem linken Schaltoperator ($number << 1) oder durch Multiplizieren unserer mit zwei.

  0001 1101
& 0000 0010
= 0000 0000 (=0, result) 

Sie können das für jedes bisschen in unserer Nummer tun. Die Binär- und unserer Zahl und die Bitmaske führt entweder zu Null, was bedeutet, dass das Bit nicht "eingestellt" oder zu einer Ganzzahl ungleich Null ist, was bedeutet, dass das Bit eingestellt wurde.

Wenn Sie eines der Bits festlegen möchten, können Sie bitweise verwenden oder:

  0001 1101
| 0010 0000 (=32, bit mask)
= 0011 1101 (=29+32)

Sie müssen jedoch eine andere Art und Weise gehen, wenn Sie ein bisschen "klären" möchten.

Ein allgemeinerer Ansatz wäre:

// To get bit n
$bit_n = ($number & (1 << $n)) != 0
// Alternative
$bit_n = ($number & (1 << $n)) >> $n

// Set bit n of number to new_bit
$number = ($number & ~(1 << $n)) | ($new_bit << $n)

Zuerst mag es ein bisschen kryptisch aussehen, aber tatsächlich ist es ziemlich einfach.

Inzwischen haben Sie wahrscheinlich herausgefunden, dass Bitfelder eine ziemlich niedrige Technik sind. Deshalb empfehle ich, sie nicht innerhalb von PHP oder Datenbanken zu verwenden. Wenn Sie eine Reihe von Flaggen haben möchten, ist es wahrscheinlich in Ordnung, aber für alles andere brauchen Sie sie wirklich nicht.

Die Klasse, die Sie gepostet haben, sieht für mich etwas ganz Besonderes aus. Zum Beispiel Dinge wie wie ... ? true : false sind Venery schlechte Praxis. Wenn Sie Bit -Felder verwenden möchten, sind Sie wahrscheinlich besser darin, einige Konstanten zu definieren und die oben beschriebene Methode zu verwenden. Es ist nicht schwer, eine einfache Klasse zu finden.

define('PERM_READ', 0);
define('PERM_WRITE', 1);

class BitField {
    private $value;

    public function __construct($value=0) {
        $this->value = $value;
    }

    public function getValue() {
        return $this->value;
    }

    public function get($n) {
        return ($this->value & (1 << $n)) != 0;
    }

    public function set($n, $new=true) {
        $this->value = ($this->value & ~(1 << $n)) | ($new << $n);
    }
    public function clear($n) {
        $this->set($n, false);
    }
}


$bf = new BitField($user->permissions);

if ($bf->get(PERM_READ)) {
    // can read
}

$bf->set(PERM_WRITE, true);
$user->permissions = $bf->getValue();
$user->save();

Ich habe kein Stück Code dieser Antwort ausprobiert, aber es sollte Ihnen beginnen, auch wenn er nicht in der Box funktioniert.

Beachten Sie, dass Sie auf 32 Werte pro Bitfeld begrenzt sind.

Andere Tipps

Hier erfahren Sie, wie Sie Bitmasks definieren können.

// the first mask.  In binary, it's 00000001
define('BITWISE_MASK_1', 1 << 0); // 1 << 0 is the same as 1

// the second mask.  In binary, it's 00000010
define('BITWISE_MASK_2', 1 << 1);

// the third mask.  In binary, it's 00000100
define('BITWISE_MASK_3', 1 << 2);

Um zu überprüfen, ob eine Bitmaske vorhanden ist (in diesem Fall in einem Funktionsargument), verwenden Sie Bitwise und Operator.

function computeMasks($masks) {
    $masksPresent = array();
    if ($masks & BITWISE_MASK_1)
        $masksPresent[] = 'BITWISE_MASK_1';
    if ($masks & BITWISE_MASK_2)
        $masksPresent[] = 'BITWISE_MASK_2';
    if ($masks & BITWISE_MASK_3)
        $masksPresent[] = 'BITWISE_MASK_3';
    return implode(' and ', $masksPresent);
}

Dies funktioniert, denn wenn Sie oder zwei Bytes (sagen wir, 00000001 und 00010000), du bekommst die beiden zusammen: 00010001. Wenn Sie und das Ergebnis und die ursprüngliche Maske (00010001 und sag, 00000001), Sie erhalten eine Maske, wenn sie vorhanden ist (in diesem Fall 00000001). Ansonsten bekommst du Null.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top