سؤال

أنا أعمل على نظام استخدام المستخدم / الإذن في PHP للحصول على برنامج نصي.

فيما يلي رمز يستخدم طريقة bitmask للأذونات التي وجدتها على phpbuilder.com.

يوجد أسفل هذا الجزء نسخة أبسط بكثير يمكن أن تفعل W3Hich نفس الشيء دون الجزء الصغير.

لقد أوصت الكثير من الناس باستخدام مشغلات البت وما إلى ذلك للإعدادات وأشياء أخرى في PHP ، لم أفهم أبدًا السبب. في الكود أدناه هناك أي فائدة من استخدام الكود الأول بدلاً من الثانية؟

<?php
/**
 * Correct the variables stored in array.
 * @param    integer    $mask Integer of the bit
 * @return    array
 */
function bitMask($mask = 0) {
    $return = array();
    while ($mask > 0) {
        for($i = 0, $n = 0; $i <= $mask; $i = 1 * pow(2, $n), $n++) {
            $end = $i;
        }
        $return[] = $end;
        $mask = $mask - $end;
    }
    sort($return);
    return $return;
}


define('PERMISSION_DENIED', 0);
define('PERMISSION_READ', 1);
define('PERMISSION_ADD',  2);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 8);

//run function
// this value would be pulled from a user's setting mysql table
$_ARR_permission = bitMask('5');

if(in_array(PERMISSION_READ, $_ARR_permission)) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';
}
?>

نسخة غير بت

<?PHP
/*
   NON bitwise method
*/

// this value would be pulled from a user's setting mysql table
$user_permission_level = 4;

if($user_permission_level === 4) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';
}

?>
هل كانت مفيدة؟

المحلول

لماذا لا تفعل هذا فقط ...

define('PERMISSION_DENIED', 0);
define('PERMISSION_READ', 1);
define('PERMISSION_ADD',  2);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 8);

//run function
// this value would be pulled from a user's setting mysql table
$_ARR_permission = 5;

if($_ARR_permission & PERMISSION_READ) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';
}

يمكنك أيضًا إنشاء الكثير من مجموعات الأذونات التعسفية إذا كنت تستخدم البتات ...

$read_only = PERMISSION_READ;
$read_delete = PERMISSION_READ | PERMISSION_DELETE;
$full_rights = PERMISSION_DENIED | PERMISSION_READ | PERMISSION_ADD | PERMISSION_UPDATE | PERMISSION_DELETE;

//manipulating permissions is easy...
$myrights = PERMISSION_READ;
$myrights |= PERMISSION_UPDATE;    // add Update permission to my rights

نصائح أخرى

الأول يتيح للأشخاص الحصول على الكثير من الأذونات - قراءة/إضافة/تحديث على سبيل المثال. المثال الثاني ، المستخدم لديه فقط PERMISSION_UPDATE.

يعمل اختبار bitwise عن طريق اختبار البتات لقيم الحقيقة.

على سبيل المثال ، التسلسل الثنائي 10010 سوف تحدد المستخدم مع PERMISSION_DELETE و PERMISSION_READ (التعرف على البت PERMISSION_READ هو العمود ل 2 ، التعريف بت PERMISSION_DELETE هو العمود لـ 16) ، 10010 في الثنائي هو 18 في عشري (16 + 2 = 18). لا تسمح لك عينة الكود الثاني بالقيام بهذا النوع من الاختبار. يمكنك إجراء فحوصات أكبر من النمط ، لكن هذا يفترض الجميع PERMISSION_DELETE يجب أن يكون أيضا PERMISSION_UPDATE, ، والتي قد لا تكون افتراضا صالحا.

ربما يكون ذلك فقط لأنني لا أستخدم Bitmasks كثيرًا ، لكنني أجد أنه في لغة مثل PHP حيث تكون إنتاجية المطور وقابلية قراءة الكود أكثر أهمية من استخدام السرعة أو الذاكرة (ضمن الحدود ، من الواضح) ، لا يوجد سبب حقيقي لاستخدام bitmasking .

لماذا لا تنشئ بدلاً من ذلك فئة تتعقب أشياء مثل الأذونات ، وتسجيلها في المستخدمين ، وما إلى ذلك؟ دعنا نسميها مصادقة. ثم ، إذا كنت تريد التحقق من أن المستخدم لديه إذن ، فيمكنك إنشاء طريقة haspermission. على سبيل المثال ،

if(Auth::logged_in() && Auth::currentUser()->hasPermission('read'))
    //user can read

ثم إذا كنت ترغب في التحقق مما إذا كان لديهم مزيج من الأذونات:

if(Auth::logged_in() && Auth::currentUser()->hasAllPermissions('read', 'write'))
    //user can read, and write

أو إذا كنت ترغب في التحقق مما إذا كان لديهم أي من مجموعة معينة من الأذونات:

if(Auth::logged_in() && Auth::currentUser()->hasAnyPermissions('read', 'write'))
    //user can read, or write

بالطبع ، قد لا تكون فكرة سيئة تحديد الثوابت ، مثل إذن _read ، والتي يمكنك فقط تحديدها لتكون "القراءة" ، وهكذا.

أجد أن هذا النهج أسهل في القراءة من Bitmasks لأن أسماء الطريقة تخبرك بالضبط بما تبحث عنه.

تعديل: إعادة قراءة السؤال ، يبدو أن أذونات المستخدم تعود من قاعدة البيانات الخاصة بك في Bitfield. إذا كان هذا هو الحال ، فسيتعين عليك استخدام مشغلي bitwise. مستخدم هو إذن في قاعدة البيانات 5 لديها PERMISSION_READ و PERMISSION_DENIED لان (PERMISSION_READ & 5) != 0, ، و (PERMISSION_DENIED & 5) != 0. لم يكن لديه PERMISSION_ADD, ، لان (PERMISSION_ADD & 5) == 0

هل هذا منطقي؟ جميع الأشياء المعقدة في مثالك البتوي تبدو غير ضرورية.


إذا كنت لا تفهم عمليات bitwise تمامًا ، فلا تستخدمها. سوف يؤدي فقط إلى الكثير من الصداع. إذا كنت مرتاحًا لهم ، فاستخدمها حيث تشعر أنها مناسبة. لا يبدو أن أنت (أو من كتب رمز bitwise) يفهمون عمليات bitwise بالكامل. هناك العديد من المشكلات في ذلك ، مثل حقيقة أن pow() يتم استخدام الوظيفة ، والتي من شأنها أن تنفي أي نوع من فائدة الأداء. (بدلاً من pow(2, $n), ، يجب عليك استخدام bitwise 1 << $n, ، علي سبيل المثال.)

ومع ذلك ، لا يبدو أن القطعتين من الكود تفعل نفس الأشياء.

حاول استخدام ما في bit.class.php في http://code.google.com/p/samstyle-php-framework/source/browse/trunk/class/bit.class.php

التحقق من قليلا:

<?php

define('PERMISSION_DENIED', 1);
define('PERMISSION_READ', 2);
define('PERMISSION_ADD',  3);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 5);


if(bit::query($permission,PERMISSION_DENIED)){
echo 'Your permission is denied';
exit();
}else{
// so on
}

?>

وتشغيل وإيقاف:

<?php

$permissions = 8;
bit::toggle(&$permissions,PERMISSION_DENIED);

var_dump($permissions); // outputs int(9)

?>

مشكلة ذلك هي إذا كان إذن _read هو قناع نفسه

if($ARR_permission & PERMISSION_READ) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';

ثم من أجل 0101 - $ rightwehave 0011 - $ rightwerequire

يتم منح الوصول ، والذي ربما لا نريده ، لذلك يجب أن يكون

if (($rightWeHave & $rightWeRequire) == $rightWeRequire) {
echo 'access granted';
}

حتى الآن ل

0101 0011

النتيجة

0001 لذلك لا يتم منح الوصول لأنه لا يساوي 0011

لكن ل

1101 0101

لا بأس مع النتيجة هي 0101

فحص السيناريو الذي تم تعيين القناع في عشري. ربما سيحتاجها شخص ما:

<?php

$max = 1073741824;
$series = array(0);
$x = 1;
$input = $argv[1]; # from command line eg.'12345': php script.php 12345
$sum = 0;

# generates all bitmasks (with $max)
while ($x <= $max) {
    $series[] = $x;
    $x = $x * 2;
}

# show what bitmask has been set in '$argv[1]'
foreach ($series as $value) {
    if ($value & $input) {
        $sum += $value;
        echo "$value - SET,\n";
    } else {
        echo "$value\n";
    }
}

# sum of set masks
echo "\nSum of set masks: $sum\n\n";

الإخراج (PHP Maskchecker.php 123):

0
1 - SET,
2 - SET,
4
8 - SET,
16 - SET,
32 - SET,
64 - SET,
128
256
512
1024
2048
4096
8192
(...)

Sum of set mask: 123

أعتقد أن المثال الأول يمنحك المزيد من التحكم في الأذونات التي يتمتع بها المستخدم بالضبط. في الثانية لديك فقط "مستوى" المستخدم ؛ يفترض أن المستويات الأعلى ترث جميع الأذونات الممنوحة لمستخدم "المستوى الأدنى" ، لذلك ليس لديك مثل هذا التحكم الجيد.

أيضا ، إذا فهمت بشكل صحيح ، الخط

if($user_permission_level === 4)

يعني أن المستخدمين فقط معهم بالضبط المستوى 4 الإذن يمكنهم الوصول إلى الإجراء - بالتأكيد تريد التحقق من أن المستخدمين لديهم على الأقل هذا المستوى؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top