2003-11-08 16:29:31 UTC
Вашему вниманию предлагается простенький класс, работающий с файлом .htpasswd
— это файл механизма стандартной авторизации веб-сервера Apache, содержащий список пользователей имеющих доступ в какой-либо каталог.
Здесь рассмотрены 2 реализации данной задачи, — с использованием таблицы и с использованием хэша. Автор первой не я, а Павел Титов, опубликовавший данный код на форуме сайта parser.ru, я лишь поправил его для себя и немного упростил. Вторая реализация сделана мной — и тут опять работает правило — всё что вы делаете (или делали), можно сделать проще, т.к. вторая реализация (с хэшем), гораздо элегантнее. Вообщем как всегда, — век живи, век учись.
Краткое описание
При создании объекта класса его конструктору — @init
передаётся строка содержащая путь к файлу .htpasswd
, конструктор пытается найти файл по указанному пути, если ему это не удаётся, он создаёт новый файл, который потом (при вызове методов класса) и записывается по указанному пути.
Класс имеет следующие методы, которые можно вызывать извне:
@setpw
— добавление нового пользователя, если пользователь с таким именем уже существует, просто меняется его пароль.@setpwCrypted
— то же самое что и выше, но вторым параметром метода передаётся не пароль, а уже его хэш. Мне это нужно для совместного использования с классом авторизации от Михаила Петрушина.@delete
— удаление пользователя.
Код класса в реализации с таблицей
############################## # $Id: htpasswd.p,v 1.19 2004/01/02 12:28:45 egr Exp $ # Класс для работы с .htpasswd # Идея Pavel Titov (pavel@titov.pp.ru) # Я маленько усовершенствовал @CLASS htpasswd ############################## # Конструктор # _tPasswd - таблица пользователь/пароль # _sFileName - полный путь к файлу .htpasswd (с путём) @init[sFileName][lHtpass] $_sFileName[$sFileName] ^try{ $lHtpass[^file::load[text;$sFileName]] $lHtpass[^lHtpass.text.match[\n][g]{^#0A}] $_tPasswd[^table::create{login password^#0A^lHtpass.match[:][g]{ }}] }{ ^if($exception.type eq file.missing || $exception.type eq parser.runtime ){ $exception.handled(1) $_tPasswd[^table::create{login password}] } } ############################## # Добавление пользователя / изменение пароля @setpw[sLogin;sPassword][lCrypted] $lCrypted[^math:crypt[$sPassword;^$apr1^$]] ^setpwCrypted[$sLogin;$lCrypted] ############################## # Добавление пользователя / изменение пароля # с передачей не самого пароля а уже его хэша # Работает просто - если пользователь есть, он сначала удаляется, # а потом записывается новый, с таким же именем, но другим паролем # Если пользователя нет, понятно что происходит в этом случае :) @setpwCrypted[sLogin;sPassword] ^if(^_tPasswd.locate[login;$sLogin]){ $_tPasswd[^_remove[$_tPasswd;^_tPasswd.line[];1]] } ^_tPasswd.append{$sLogin $sPassword} ^_save[] ############################## # Удаление пользователя @delete[sLogin] ^if(^_tPasswd.locate[login;$sLogin]){ $_tPasswd[^_remove[$_tPasswd;^_tPasswd.line[];1]] } ^_save[] ############################## # Сохранение .htpasswd @_save[] $result[^_tPasswd.menu{${_tPasswd.login}:$_tPasswd.password^#0A}] ^result.save[$_sFileName] $result[] ############################## # http://parser.ru/forum/?id=3803 ## удаление строк из таблицы # результат - таблица # t - имя таблицы # from - начиная с какой строки удалять (!!! нумерация строк с 1) # count - сколько строк удалять # пример: $mytable[^remove[$mytable;1;10]] - удалит первые 10 строк @_remove[t;from;count] ^if(def $t){ $result[^t.select((^t.line[]<$from) || (^t.line[]>=$from+$count))] }
Код класса в реализации с хэшем
Данная версия работает быстрее при использовании файлов .htpasswd
с большим количеством записей (пользователей). Правда при количестве пользователей менее десятка, она вряд ли быстрее первой и кушает немного больше пямяти, но на спичках экономить не следует, и этим можно пренебречь.
############################## # $Id: htpasswd.p,v 1.22 2004/01/12 18:14:15 egr Exp $ # Класс для работы с .htpasswd # Идея Pavel Titov (pavel@titov.pp.ru) # Я сильно усовершенствовал реализацию - вместо таблиц используется хэш @CLASS htpasswd ############################## # Конструктор # Параметр: # sFileName - полный путь к файлу .htpasswd (вида /path/.htpasswd) # Поля класса: # _sFileName - полный путь к файлу .htpasswd (вида /path/.htpasswd) # _hPasswd - хэш пользователь/пароль @init[sFileName][lHtpass] $_sFileName[$sFileName] ^try{ $lHtpass[^file::load[text;$sFileName]] $lHtpass[^lHtpass.text.match[\n][g]{^#0A}] $lHtpass[^table::create{login password^#0A^lHtpass.match[:][g]{ }}] }{ ^if($exception.type eq file.missing || $exception.type eq parser.runtime ){ $exception.handled(1) $lHtpass[^table::create{login password}] } } $_hPasswd[^lHtpass.hash[login]] ############################## # Добавление пользователя / изменение пароля @setpw[sLogin;sPassword][lCrypted] $lCrypted[^math:crypt[$sPassword;^$apr1^$]] ^setpwCrypted[$sLogin;$lCrypted] ############################## # Добавление пользователя / изменение пароля # с передачей не самого пароля а уже его хэша @setpwCrypted[sLogin;sPassword] ^if(def $sLogin && !^sLogin.match[:]){ ^_hPasswd.add[ $.[$sLogin][ $.login[$sLogin] $.password[$sPassword] ] ] ^_save[] } ############################## # Удаление пользователя @delete[sLogin] ^if(def $_hPasswd.[$sLogin]){ ^_hPasswd.delete[$sLogin] ^_save[] } ############################## # Сохранение .htpasswd @_save[] $result[^_hPasswd.foreach[login;password]{${login}:${password.password}}[^#0A]] ^try{ ^result.save[$_sFileName] $result[] }{ $exception.handled(1) $result[Невозможно записать $_sFileName] }
Пример вызова
Внимание! — класс не будет работать если вызывать его методы статически. А вообще, использовать его очень просто — сначала создаётся объект класса, а затем вызывается нужный метод:
$oPass[^htpasswd::init[/path/to/.htpasswd]] # Добавление (изменение пароля) пользователя с передачей # незашифрованного пароля ^oPass.setpw[$sUserName;$sPasswd] # Добавление (изменение пароля) пользователя с передачей # хэша пользовательского пароля, полученного с помощью math:crypt ^oPass.setpwCrypted[$sUserName;$sPasswd] # Удаление пользователя ^oPass.delete[$sUserName]
Загрузить пример (1-я реализация)
Загрузить пример (2-я реализация)
Примечание: Загружаемые файлы находятся в кодировке UTF-8.