Автореферат
Библиотека
Ссылки
Отчет о поиске
Роликовый спорт
Автобиография
Автореферат Библиотека Ссылки Отчет о поиске Роликовый спорт

Гошко Владислав Викторович

Донецкий национальный технический университет

Факультет: вычислительной техники и информатики

Специальность: экономическая кибернетика

Тема выпускной работы: Маркетинговый анализ средств защиты от спама

Руководитель: Костин Валерий Иванович

Гошко В.В.

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


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

В данной статье я рассмотрю работу с базами данных на языке программирования Perl. Для удобства начнем от маленького к большому. Для начала давайте рассмотрим обычный файл как базу данных, т.е. обычный файл можно представить как определенно сформатированый текст.

Файл будет отформатирован следующим образом:

Name1|Value1#Value2#Value3#...#ValueN
Name2|Value1#Value2#Value3#...#ValueN
Name3|Value1#Value2#Value3#...#ValueN
...
NameN|Value1#Value2#Value3#...#ValueN

Почему разделителями я выбрал именно "|" и "#"? Потому что они не явлются безопасными символами (из RFC 2396). По той же причине можно было выбрать разделители любой символ кроме латинских букв, цифр, и вот этих:

";", "/", "?", ":", "@", "&", "=", "+", "$", ",", "-", "_", ".", "!", "~", "*", "'", "(", ")"

Эти разделители (кроме вышеописаных символов) могут использоваться в значениях или в именах переменных, только нужно будет использовать модуль URI::Escape, для того чтобы переменные с этими разделителями не испортили структуру...

Специално для работы с нашими базами данных создадим модуль simple_db.pm

Итак начнем:

#!/usr/bin/perl

# создаем пакет
package simple_db;

use Exporter;
# как и говорилось используем модуль для перевода небезопасных символов в
# формат %XX
use URI::Escape;

@ISA=("Exporter");
@EXPORT=qw(&opendb &closedb %g);
# экспортируем используемые функции, а также
# хеш %g для того чтобы функция знала в какой файл записывать
# изменения хеша вводимого в аргументах
sub opendb{
my($h,$file)=@_;
my($name,$vals,@values);
local(*DB);
open(DB,$file) or return 0;
# блокируем файл, на тот случай если во время чтения кто-то
# захочет изменить файл
# (совместная блокировка - для чтения)
flock(DB,1);
while(){
chomp;
($name,$vals)=split(/\|/,$_,2);
next if !$name;
$name = uri_unescape($name);
@values = split(/#/,$vals);
# если значений много создаем анонимный массив, иначе просто присваиваем
# одно значение
if($#values){
for(0..$#values){
# переводим символы из %XX формата в нормальный вид
$values[$_]=uri_unescape($values[$_]);
}
$$h{$name}=[@values];
}else{
$vals = uri_unescape($vals);
$$h{$name}=$vals;
}
}
close(DB);
# записываем в глобальный хеш ассоциацию ссылки на хеш с открытым файлом
$g{$h}=$file;
}

sub сlosedb{
my($h)=@_;
my($key,$val,$fn);
# по имени хеша получаем имя файла
$fn = $g{$h};
local(*DB);
# выходим из функции если файла не существует
return if !(-e $fn);
open(DB,">$fn") or return 0;
# замыкаем файл
# (монопольная блокировка - для записи)
flock(DB,2);
while(($key,$val) = each %$h){
# обратно создаем формат, переводя небезопасные символы в формат %XX
print DB uri_escape($key)."|";
if(ref $val){
for(0..$#$val){
$$val[$_]=uri_escape($$val[$_]);
}
print DB join "#",@$val;
}else{
$val=uri_escape($val);
print DB $val;
}
print DB "\n";
}
close(DB);
}
1;

Если вам нужно открывать файл с определенными правами, то в функциях opendb() и closedb(), нужно просто заменить open на sysopen, по следующему формату: sysopen FILEHANDLE, FILENAME, MODE, PERMS; и все.

Использование довольно простое, возьмем какой-нибудь файл test.pl. В этой же директории должен лежать и модуль simple_db.pm. Вот test.pl:

#!/usr/bin/perl

use simple_db;

# открываем файл test.db и ассоциируем с ним хеш %h, иначе умираем
opendb(\%h,"test.db") or die $!;
# добавляем значения в хеш
$h{'supa|var'}=["special#","tes#t"];
# также легко можно добавить массив
@tmp = ("array","tester");
# добавили ...
$h{'arr'}=\@tmp;
# или добавляем массив так
$h{'arr2'}=["some","vars"];
closedb(\%h) or die $!;

Данным образом будет создам файл test.db в текущей директории. С переменной 'supa|var' и значениями 'speacial#' и 'tes#t', и т.д. Я специально использовал небезопасные символы, а со второй и третьей переменной все в порядке - там нет небезопасных символов...

А теперь давайте посмотрим что записано в файле test.db:

supa%7Cvar|special%23#tes%23t
arr|array#tester
arr2|some#vars

Т.е. эти символы не помешали нашей структуре файла, они всего лишь были переведены в %XX формат. А теперь просмотрем всю базу:

#!/usr/bin/perl

use simple_db;

opendb(\%h,"test.db") or die $!;
while(($key,$val) = each %h){
print $key." = ";
if(ref $val){
# здесь если значение переменной ссылка на массив
print join " ; ",@$val;
}else{
print $val;
}
print "\n";
}
closedb(\%h) or die $!;

При выводе база будет выглядеть так:

supa|var = special# ; tes#t
arr = array ; tester
arr2 = some ; vars

Очищаем базу - просто очищая хеш, т.е. %h=(), или можно просто удалить файл следующим образом:

unlink "test.db" or die $!;

А при открытии базы открыть файл в режиме создания, т.е. перед opendb() сделать следующее:

# $filename - в данном случае имя нашего файла
if(!(-e "$filename")){
open(FILE,">$filename") or die $!;
close(FILE);
}

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

Вы можете попробовать создать свою базу данных, с помощью классов можно создать вполне приличную базу данных...

А теперь давайте расмотрим другие базы данных.

Начнем с портированной в вашу систему базу данных (их может быть несколько).

Функция dbmopen() довольна стара и поэтому позволяет использовать лишь ту библиотеку DBM c которой был построен Perl. Но по ходу статьи рассмотрим и более новые методы.

Вот пример с dbmopen():

#!/usr/bin/perl

use Fcntl; # специально для таких перменных как O_RDWR, O_CREAT
# O_RDWR - права: чтение, запись
# O_CREAT - создать файл если он не существует

dbmopen(%HASH,$FILENAME,O_RDWR|O_CREAT, 0666) or die "Cant open $FILENAME: $!\n";
# заносим данные в базу данных
$HASH{KEY}="VALUE";
# проверяем существует ли ключ
if(exists $HASH{KEY}){
# что-то делаем с информацией полученной из базы данных
$info = $HASH{KEY};
}
# удаляем какой-нибудь ключ из базы
delete $HASH{SOME_KEY};
dbmclose(%HASH);

Также в начале программы можно добавить:

use NDBM_File;
или
use SDBM_File;
или
use GDBM_File;
или
use DB_File;

Данные модули просто переодпределяют стандартный вариант, с которым был построен Perl. Есть также другой способ открытие базы данных - tie и untie. Делается это так:

#!/usr/bin/perl

use DB_File; # здесь это обязательно, т.к. в функции tie() мы задаем модуль
use Fcntl;

tie(%HASH,"DB_File",$FILENAME,O_RDWR|O_CREAT, 0666) or die "Can't open $FILENAME: $!\n";
# все те же манипуляции с хешем, которые описывались выше
# ...
# а потом
untie(%HASH);

Очищаются базы также как и в моем примере, т.к. я свой пример делал по подобию этих баз. Но также как и мой пример, данные базы не могут хранить сложные структуры. Для это требуется модуль DB_File и модуль MLDBM.

Модуль MLDBM может хранить в хеше более сложные структуры, чем просто числа и скаляры. Если его у ваc нет, то вы можете его скачать из интернета, вот так: запускаете программу ppm из дистрибутива Perl. И пишите: "install MLDBM" - все должно пройти успешно.

Использование вот такое:

#!/usr/bin/perl

use MLDBM 'DB_File';
use Fcntl; # для O_RDWR, O_CREAT и т.д.

tie(%h, "MLDBM", "glob.db", O_RDWR|O_CREAT, 0666) or die "Couldn't tie DB_File $users: $!; aborting";
$usr{synthetic}->{password}="matrix reloaded";
$h{users}=\%usr;
untie %h;

Таким образом была создана база данных glob.db, в которой есть ключ 'users', далее в котором есть пользователь 'synthetic' с еще одним вложеным хешем в котором есть ключ 'password' со значением 'matrix reloaded'. Такая структура очень удобна и легко запрашиваема. Далее посмотрим как мы проверяем, то что создали:

#!/usr/bin/perl

use MLDBM 'DB_File';
use Fcntl; # для O_RDWR, O_CREAT и т.д.

$access=0;
tie(%h,"MLDBM","glod.db",O_RDWR|O_CREAT,0666) or die "Couldn't tie DB_File $users: $!; aborting";
while(($key,$val) = each %h){
if($key eq "users"){
if($val->{synthetic}->{password} eq "matrix reloaded"){
$access=1;last;
# если все правильно завершаем цикл
}
}
}
untie(%h);
if($access){
print "Matrix has you...";
}else{
print "Follow the white rabbit";
}

С удалением нужно немного по-другому, через временный хеш:

tie(%h,"MLDBM","glob.db",O_RDWR|O_CREAT,0666) or die "Couldn't tie DB_File $users: $!; aborting";
%tmp=%h;
delete $tmp{users}->{'somebody'};
%h=%tmp;
untie %h;

Добавлять тоже через временный хеш:

tie(%h,"MLDBM","glob.db",O_RDWR|O_CREAT,0666) or die "Couldn't tie DB_File $users: $!; aborting";
%tmp=%h;
$tmp{users}->{'morpheus'}->{password}='zion';
%h=%tmp;
untie %h;

И в моем примере и других базах используется работа с хешами, поэтому давайте рассмотрим несколько примеров работы с хешами...

Сортировка ключей хеша по алфавиту:

foreach $key (sort keys %unsorted){
$val = $unsorted{$key};
# здесь переборка ключей хеша по алфавиту
# делаем что-то c $key и $val
}

Сортировка по ассоциирорванным значениям:

foreach $key (sort {$unsorted{$a} cmp $unsorted{$b} } keys %unsorted){
$val = $unsoreted{$key};
# что-то делаем с $key и $val...
}

Сортировка по длине значений, (почти также как и просто по значениям):

foreach $key (sort {length($unsorted{$a}) <=> length($unsorted{$b}) } keys %unsorted){
$val = $unsoreted{$key};
# что-то делаем с $key и $val...
}

Дальше рассмотрим небольшие примеры работы с базами данных MySQL, при помощи модуля DBI и драйвера для работы с MySQL - DBD::mysql. Эти модули также можно установить через ppm. А теперь посмотрим пример работы с MySQL.

#!/usr/bin/perl

use DBI;

# настройки SQL сервера #######################################################
$user = "synthetic"; # логин и
$password = "test"; # пароль для доступа к серверу
$host = "localhost"; # адрес SQL сервера
$db = "site"; # база данных с которой соединяемся
$port = 3306; # порт (взят по умолчанию)
$driver = "mysql"; # это драйвер для базы данных, т.е. вы можете указать
# драйвер своей базы и спокойно соединятся с ней
# (естественно зная ее семантику)
###############################################################################

# данные - просто для проверки
$login = "Vlad";
$pass = "isitreal";

$conn = "DBI:$driver:database=$db;host=$host;port=$port";
# RaiseError => 1 - сообщать об ошибках
$dbh = DBI->connect($conn, $user, $password, {RaiseError => 1});
# задали название тэйбла - для дальнейшего использования
$table = "users";
# создаем тэйбл "users"
$query = "CREATE TABLE .$table(username char(16) not null,pass char(16) not null)";
# создали
$dbh->do($query);
# отсоединилсь
$dbh->disconnect();

Не особо сложными манипуляцимя добавляем данные в тэйбл:

# вся предыдущая инициализация
$query = sprintf("INSERT INTO .$table (username, pass) VALUES ('%s', '%s')", $login, $pass);
# выполнили...
$dbh->do($query);
# и т.д.

Выбираем из базы:

# вся предыдущая инициализация.
# создаем запрос к базе и выбираем все из тэйбла users
$sth = $dbh->prepare("select * from .users");
# выполнили
$sth->execute();
while($row = $sth->fetchrow_arrayref()){
# в данном случае:
# $row->[0] - логин (username)
# $row->[1] - пароль (pass)
print $row->[0]." ".$row->[1];
} # обязательно (!) говорим, что завершили
$sth->finish();

Удаляем тэйбл, если он существует:

# вся предыдущая инициализация
$query = "DROP TABLE IF EXISTS .$table";
# выполнили...
$dbh->do($query);
# и т.д.

Вот собственно и все, в данной статье я не стал особенно глубоко рассматривать работу с базами SQL, потому как это довольно большая тема и требует отдельной статьи (если не книжки)...

Удачи в создании систем управления базами данных!