Разработчику. Сборник рецептов PHP
Задавайте вопросы

Работа с базами данных DBM

Вернуться назад

Задача

Необходима более устойчивая и масштабируемая технология хранения простых данных, чем текстовых файлов.

Решение

Для доступа к базе данных типа DBM следует использовать уровень абстракции DBA:

$dbh = dba_open('fish.db','c','gdbm') or die($php_errormsg);

// извлекаем и модифицируем значения
if (dba_exists('flounder',$dbh)) {
     $flounder_count = dba_fetch('flounder',$dbh);
     $flounder_count++;
     dba_replace('flounder',$flounder_count);
     print "Updated the flounder count.";
} else {
     dba_insert('flounder',1);
     print "Started the flounder count.";

}

// больше нет ни одной тилапии
dba_delete('tilapia',$dbh);

// какая у нас рыбка?
for ($key = dba_firstkey($dbh); $key !== false; $key = dba_nextkey($dbh)) {
     $value = dba_fetch($key);
     print "$key: $value\n";

}

dba_close($dbh);

Обсуждение

PHP способен поддерживать несколько различных типов машин баз данных DBM: GDBM, NDBM, DB2, DB3, DBM и CDB. Уровень абстракции DBA позволяет использовать одни и те же функции на любой машине DBM. Все машины хранят пары ключ/значение. Можно выполнять циклы по всем ключам базы данных, извлекать значение, связанное с конкретным ключом, и определять, есть ли определенный ключ. И ключи, и значения представляют собой строки.

Следующая программа поддерживает список имен пользователей и паролей с помощью базы данных DBM. Имя пользователя – это первый аргумент командной строки, а пароль – второй аргумент. Если имя пользователя уже существует в базе данных, то пароль заменяется данным паролем; в противном случае комбинация из имени пользователя и пароля добавляется в базу данных:

$user = $_SERVER['argv'][1];
$password = $_SERVER['argv'][2];

$data_file = '/tmp/users.db';

$dbh = dba_open($data_file,'c','gdbm') or die("Can't open db $data_file");

if (dba_exists($user,$dbh)) {
     print "User $user exists. Changing password.";
} else {
     print "Adding user $user.";

}

dba_replace($user,$password,$dbh) or die("Can't write
                         to database $data_file");

dba_close($dbh);

Функция dba_open() возвращает дескриптор файла DBM (или false в случае ошибки). Она принимает три аргумента. Первый аргумент – это имя файла DBM, а второй аргумент – режим открытия файла. Режим 'r' открывает доступ к существующей базе данных только на чтение, а 'w' открывает существующую базу данных на чтение и запись. Режим 'c' открывает доступ к базе данных на чтение/запись и создает базу данных, если она не существует. Последний режим, 'n', делает то же самое, что и режим 'c', но если база данных уже существует, то очищает ее. Третий аргумент функции dba_open() указывает используемый DBM-обработчик; в данном примере это 'gdbm'. Чтобы определить, какой DBM-обработчик был скомпилирован во время инсталляции PHP, загляните в секцию «DBA» вывода функции phpinfo(). Строка «Supported handlers» показывает то, что было выбрано.

Функция dba_exists() позволяет определить, есть ли такой ключ в базе данных DBM. Она принимает два аргумента: строку-ключ и дескриптор файла DBM. Она ищет ключ в файле DBM и возвращает true, если находит его (или false, если поиск неудачен). Функция dba_replace() принимает три аргумента: ключ-строку, строковое значение и дескриптор файла DBM. Она помещает ключ/значение в файл DBM. Если элемент с данным ключом уже существует, она заменяет этот элемент новым значением.

Для закрытия базы данных вызовите функцию dba_close(). Файл DBM, открытый функцией dba_open(), автоматически закрывается при завершении работы сценария, но необходимо явно вызвать функцию dba_close(), чтобы закрыть постоянные соединения, созданные функцией dba_popen().

С помощью функций dba_firstkey() и dba_nextkey() можно пройти в цикле по всем ключам в файле DBM, а функция dba_fetch() позволяет извлекать значения, связанные с каждым ключом. Приведенная ниже программа вычисляет общую длину всех паролей в файле DBM:

$data_file = '/tmp/users.db';
$total_length = 0;
if (! ($dbh = dba_open($data_file,'r','gdbm'))) {
     die("Can't open database $data_file");

}

$k = dba_firstkey($dbh);
while ($k) {
     $total_length += strlen(dba_fetch($k,$dbh));
     $k = dba_nextkey($dbh);

}

print "Total length of all passwords is $total_length characters.";

dba_close($dbh);

Функция dba_firstkey() инициализирует переменную $k значением первого ключа в файле DBM. При каждом прохождении цикла while функция dba_fetch() извлекает значение, соответствующее ключу $k, и переменная $total_length увеличивается на длину значения (вычисленного посредством функции strlen()). С помощью функции dba_nextkey() переменной $k присваивается значение следующего ключа из файла.

Функция serialize() позволяет реализовать хранение сложных данных в файле DBM – точно так же, как это делается в случае текстового файла. Однако данные в файле DBM могут быть индексированы ключом:

$dbh = dba_open('users.db','c','gdbm') or die($php_errormsg);

// читаем данные и выполняем обратное преобразование
// из последовательной формы
if ($exists = dba_exists($_REQUEST['username'])) {
     $serialized_data = dba_fetch($_REQUEST['username'])
                                         or die($php_errormsg);
     $data = unserialize($serialized_data);
} else {
     $data = array();

}

// обновляем значения
if ($_REQUEST['new_password']) {
     $data['password'] = $_REQUEST['new_password'];

}

$data['last_access'] = time();

// записываем данные обратно в файл
if ($exists) {
     dba_replace($_REQUEST['username'],serialize($data));
} else {
     dba_insert($_REQUEST['username'],serialize($data));

}

dba_close($dbh);

Несмотря на то что код этого примера может сохранять данные нескольких пользователей в одном файле, нельзя найти, например, время последней регистрации пользователя без выполнения цикла по всем ключам файла. Структурные данные такого типа относятся к базам данных SQL.

В некоторых областях каждый DBM-обработчик ведет себя по-разному. Например, GDBM предоставляет внутреннюю блокировку. Если один процесс открыл файл GDBM в режиме чтения/записи, то еще один вызов функции dba_open() для открытия того же самого файла в режиме чтения/записи закончится неудачей. Однако обработчик DB3 не предоставляет внутренней блокировки; для этого необходимо написать дополнительный код, как объясняется в рецепте Блокировка файла для текстовых файлов. Две DBA-функции также имеют особенности, связанные с типами баз данных: dba_optimize() и dba_sync().

Функция dba_optimize() вызывает специфическую для обработчика функцию оптимизации файла DBM. В настоящее время она реализована только для GDBM, при этом вызывается его функция gdbm_reorganize(). Функция dba_sync() вызывает специфическую для обработчика функцию синхронизации файла DBM. В случае DB2 и DB3 вызывается их функция sync(). В случае GDBM вызывается его функция gdbm_sync(). Если применяются другие DBM-обработчики, то ничего не выполняется.

Использование базы данных DBM представляет собой шаг вперед по сравнению с текстовыми файлами, но при этом большинство возможностей SQL-баз данных недоступны. Структура данных ограничена парами ключ/значение, а устойчивость блокировки сильно зависит от DBM-обработчика. Все же выбор DBM-обработчиков может быть вполне оправдан, если требуется в основном только чтение данных при большой нагрузке.

См. также

Документацию по функциям DBA на http://www.php.net/dba; подробную информацию по DBM-обработчикам для баз данных DB2и DB3 на http://www.sleepycat.com/faq.html#program; информацию по GDBM на http://www.gnu.org/direc-tory/gdbm.html или на http://www.mit.edu:8001/afs/athena.mit.edu/project/gnu/doc/html/gdbm_toc.html; информацию по CDB на http://cr.yp.to/cdb.html;

Вернуться назад

Рейтинг@Mail.ru

Яндекс.Метрика

Индекс цитирования


Рейтинг Сайтов ДОСКИ.РУ