Чтобы установить определенный бит, используется операция включающей дизъюнкции (значение | значение). Допустим, текущее значение флага $value равно 3 (это означает, что установлен нулевой и первый биты), а вы хотите дополнительно установить второй бит (не забывайте, что нумерация начинается с нуля). Тогда можно воспользоваться операцией включающей дизъюнкции текущего значения флага с константой 4 (2 во второй степени):
$value = 3;
$value |= 4;
Теперь значение стало равно 7. В двоичном виде операция выглядит следующим образом:
0 0 0 0 0 1 1
| 0 0 0 0 1 0 0
= 0 0 0 0 1 1 1
Переключение бита
Переключение бита - установка его значения равным 1, если он был равен 0, и наоборот, - осуществляется операцией исключающей дизъюнкции (value ^ value). Если значение равно 3, а мы хотим переключить первый бит (который равен 1, поскольку в двоичной системе счисления число 3 выглядит как 0000011), то следует написать:
$value = 3;
$value ^= 2;
В результате получится 1. В двоичном виде:
0 0 0 0 0 1 0
^ 0 0 0 0 0 1 0
= 0 0 0 0 0 0 1
Сброс бита
Сброс бита осуществляется очень просто: сначала нужно убедиться, что он включен, а затем обратить его. Это требует двух поразрядных операций (value & ~value). Чтобы сбросить первый бит в значении 3, можно использовать следующие строки:
$value = 3;
$value $= ~2;
Проверка значения бита
Чтобы проверить, установлен ли бит, используется операция конъюнкции. Эта операция сравнивает два значения и возвращает 1 для тех позиций, где биты в обоих числах оказались равны 1. Скажем, чтобы проверить, установлен ли первый бит в константе 3, можно написать:
if(2 & 3)
//соответствующий код
Поразрядный сдвиг
Для сдвига битов вправо или влево можно использовать операторы сдвига >> и << (например, значение << количество_позиций). Так, сдвиг значения 1 влево на одну позицию даст в результате двоичное значение 10:
0 0 0 0 0 0 1
<< 0 0 0 0 0 1 0
= 0 0 0 0 0 1 0
Поразрядный сдвиг может использоваться для установки значений битов (см. пример).
Приоритет операторов
Помните, что приоритет поразрядных операторов ниже, чем приоритет арифметических операторов. Операторы в выражении 1 + 2 | 3 будут выполняться в следующем порядке: (1 + 2) | 3. Кроме того, необходимо помнить, что поразрядные операторы имеют более низкий приоритет, чем операторы сравнения. Будьте внимательны и избегайте условий вроде if(2 & 3 != 0). Вместо проверки на то, установлен ли второй бит в значении 3 (а он установлен), в данном выражении сначала проверяется значение условия 3 != 0, а это, конечно, правда (true). В результате мы получаем выражение 2 & 1, возвращающее 0, а это совсем не то, что мы хотели.
Пример
Вернемся к примеру с увлечениями пользователя, который мы использовали выше. Предположим, что в программе определены четыре возможных увлечения: чтение, программирование, сочинительство и путешествия. В начале каждому хобби мы поставим в соответствие свой бит:
-
чтение - 0
-
программирование - 1
-
сочинительство - 2
-
путешествия - 3
В двоичном виде эти значения представлены следующим образом:
-
Чтение: 0 0 0 0 0 0 1
-
Программирование: 0 0 0 0 0 1 0
-
Сочинительство: 0 0 0 0 1 0 0
-
Путешествия: 0 0 0 1 0 0 0
Определить виды увлечений в тексте сценария можно обычным поразрядным сдвигом:
-
define("HOBBY_READING":, 1 << 0);
-
define("HOBBY_PROGRAMMING", 1 << 1);
-
define("HOBBY_WRITING", 1 << 2);
-
define("HOBBY_HIKING", 1 << 3);
Если пользователь выбирает в качестве хобби сочинительство и программирование, можно создать комбинацию битов при помощи оператора | (включающая дизъюнкция):
$pattern = HOBBY_WRITING | HOBBY_PROGRAMMING;
После этого вы можете проверить, действительно ли пользователь выбрал сочинительство в качестве своего хобби, обратившись к значению соответствующего бита:
printf ("Сочинительство %s выбрано.", (HOBBY_WRITING & $pattern) ? "": "не");
Для сброса бита, связанного с сочинительством, можно использовать следующую строку:
$pattern &= -HOBBY_WRITING;
Проверка уровня прав доступа осуществляется с помощью функции $auth-> have_perm("admin"). В качестве параметра ей передается уровень прав доступа; в нашем примере это $auth->have_perm("admin"). Функция проверяет, имеет ли пользователь привилегию admin. Если пользователь имеет необходимые права доступа, то функция возвращает true, иначе - false.
У каждого пользователя есть соответствующие привилегии. В реализации класса Example_Auth информация о привилегиях записывается в таблицу auth_user базы данных MySQL. Вы уже видели это поле в текстах сценариев:
perms varchar (255)
Список допустимых уровней доступа определяется в классе, производном от Perm, в переменной класса $permissions. Для класса Example_Perm установлены следующие разрешения на доступ:
-
var $permissions = array(
-
"user" =>1
-
"author" =>2
-
"editor" =>4
-
"supervisor" =>8
-
"admin" =>16
-
);
Права доступа переводятся в двоичные значения внутренними функциями класса; при соответствующих вычислениях используются конъюнкция и дизъюнкция. Значения в определенном выше ассоциативном массиве определяют свою комбинацию битов для каждого уровня прав доступа. Хотя все это выглядит достаточно сложно, использование комбинации битов очень эффективно для представления подобных данных. В частности, этот механизм дает возможность работать с уровнями, наследующими права доступа более низких уровней. Если вы хорошо продумали соответствующие комбинации битов, уровень admin может автоматически получить все привилегии уровня user.
У значений, заданных по умолчанию, подобная модель поведения отсутствует: уровень admin отличается от уровня user, и пользователь, принадлежащий к группе admin, не получит доступа к функциональным возможностям, установленным в элементе $auth->have_perm("user"). Чтобы было понятнее, посмотрим, как библиотека PHPLib вычисляет комбинации битов.
-
Допустим, определенные возможности доступны только для уровня user. Этому уровню соответствует константа 1.
-
Пусть пользователю соответствует уровень доступа admin, которому соответствует число 16.
-
Указанные операнды соединяются конъюнкцией, в результате получается 0 (проверьте сами: print(16 & 1);). Результат (0) не совпадает с константой, определенной для уровня user (требуется 1), поэтому доступ невозможен.
Суть этих вычислений заключается в том, что библиотека PHPLib проверяет, установлен ли в комбинации разрядов, заданной в качестве аргумента функции $perm-> have_perms(), бит, соответствующий правам доступа данного пользователя. Такой механизм дает возможность определять сложные комбинации прав доступа.
Рассмотрим другой пример. Предположим, что имеется четыре уровня прав доступа: admin, editor_in_chief, editor и author (администратор, главный редактор, редактор, автор). Вы хотите, чтобы редактор (editor) не мог вносить на рассмотрение ответственных лиц никаких материалов (это прерогатива автора - author), но все прочие группы должны наследовать права доступа, установленные для более низких уровней. Окончательно система полномочий выглядит следующим образом:
-
admin : наследует editor_in_chief, editor, author
-
editor_in_chief: наследует editor, author
-
editor
-
author
Чтобы вычислить комбинацию битов для каждой группы пользователей, следует начать с нижнего уровня, author, с комбинации 1 (означающей, что установлен самый правый, нулевой бит). Если бы мы хотели, чтобы редактор наследовал уровень автора, мы бы использовали его комбинацию разрядов и установили следующий бит (1 | 2). Однако в данном примере мы хотим разделить права этих двух групп, поэтому мы задаем уровень editor как комбинацию разрядов, дающую значение 2 (двоичное 10).
Теперь, если редактор запрашивает страницу, доступную только для группы author, он не получает к ней доступа:
-
Требуемый уровень (author): 1.
-
Действительный уровень (editor): 2.
-
Конъюнкция 1 и 2 (1 & 2) равна 0, а это не соответствует требуемому уровню.
Следующий, более высокий уровень (второй бит, то есть третий справа) - это editor_in_chief, наследующий уровням editor и author. Это означает, что в комбинации разрядов уровня главного редактора должны быть установлены нулевой и первый биты, а мы дополнительно устанавливаем второй бит (2 во второй степени, или 4): 1 | 2 | 4. В результате получаем 7.
Проверим правильность полученного результата:
-
Требуемый уровень (editor): 2.
-
Текущий уровень (editor_in_chief): 7.
-
Конъюнкция 7 и 2 (7 & 2) дает 2, то есть требуемый уровень.
Осталось рассмотреть уровень администратора, который также наследует всем низшим уровням. Следует использовать выражение 7 | 8 (константа 8, или 2 в третьей степени, используется для установления третьего бита). Результат равен 15. Проверяем:
-
Требуемый уровень (editor_in_chief): 7.
-
Текущий уровень (admin): 15.
-
Конъюнкция 15 и 7 (15 & 7) дает нам 7, что соответствует требуемому уровню.
Таким образом, наши права доступа определяются следующим образом:
define("PHPLIB_PERM_AUTHOR", 1 | 0);
define("PHPLIB_PERM_EDITOR", 1 | 0);
define("PHPLIB_PERM_EDITOR_IN_CHIEF" 1 | 2 | 4);
define("PHPLIB_PERM_ADMIN", 1 | 2 | 4 | 8);
var $permissions = array(
"author" => PHPLIB_PERM_AUTHOR,
"editor" => PHPLIB_PERM_EDITOR,
"editor_in_chief" =>PHPLIB_PERM_EDITOR_IN_CHIEF,
"admin" => PHPLIB_PERM_ADMIN
);
Заключение
В этой главе вы познакомились с основными классами и способами применения библиотеки PHPLib. Она является мощным инструментом, обеспечивающим решение многих проблем, которые неизбежно возникают при создании Web-приложений. Этой библиотекой легко пользоваться, если вы позаботитесь о том, чтобы предварительно создать на ее основе продуманный механизм, отвечающий вашим потребностям. Библиотека PHPLib - прекрасный каркас для реализации процедур управления всеми аспектами сеансов работы пользователей и аутентификации.
В следующей главе мы рассмотрим образец использования библиотеки PHPLib в реальном приложении. Кроме того, вы познакомитесь еще с одним классом - Template, - позволяющим добиться более полной развязки кода и макета.