لماذا يجب أن أستخدم bitwise/bitmask في PHP؟
-
21-09-2019 - |
سؤال
أنا أعمل على نظام استخدام المستخدم / الإذن في 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 الإذن يمكنهم الوصول إلى الإجراء - بالتأكيد تريد التحقق من أن المستخدمين لديهم على الأقل هذا المستوى؟