Семь веб-интерфейсов к электронной почте. Выберите лучший!
Сергей Супрунов
Alias /mail/ /usr/local/www/ilohamail/
; Initialize session on request startup
session.auto_start = 1
; Initialize session on request startup
session.auto_start = 1
/usr/libexec/sendmail/sendmail -oi -t
$addedentry = $AddressBook->AddEntry($headerinfo->(ISDecode(fromaddress));
$addedentry = $AddressBook->AddEntry(ISDecode($headerinfo->fromaddress);
function PageHeader($echo=1, $frame=0) {
$header = "";
if ($_SESSION["locale"] == "ru_RU") {
$header = "\n";
} else {
$header = "\n";
}
; Initialize session on request startup
session.auto_start = 0
-----------------------------------------------------------------------------------------------------------------
Полезные советы по FreeBSD
Сергей Супрунов
# script /var/log/build.log
# make buildworld
# exit
# /usr/local/sbin/pkg_cutleaves -x
$ cat /usr/src/sys/`uname -p`/conf/`uname -i`
$ touch arch`date "+%Y-%m-%d"`
$ echo a`echo b\`echo c\\\`echo d\\\`c\`b`a
# portsnap fetch && portsnap update
-----------------------------------------------------------------------------------------------------------------
Полезные советы по Apache
Сергей Супрунов
AllowOverride None
AllowOverride All
Alias /proect/ /usr/local/www/htdocs/project/
Checkspelling on
-----------------------------------------------------------------------------------------------------------------
Упаковщики исполняемых файлов в Linux/BSD
Крис Касперски
Листинг 1. Дизассемблерный листинг расшифровщика, внедряемого ELFCrypt в файл (как он выглядит в hiew)
:entrypoint
.080495DC: EB02 jmps .0080495E0 ; переходим на расшифровщик
.080495DE: 06 push es ; \ мусор, оставленный...
.080495DF: C6 ??? ; / ...транслятором ассемблера
.080495E0: 60 pushad ; сохраняем все регистры в стеке
.080495E1: 9C pushfd ; сохраняем флаги в стеке
.080495E2: BEC0820408 mov esi, 0080482C0 ; начало расшифровываемого фрагмента
.080495E7: 8BFE mov edi, esi ; EDI := EDI (расшифровка на месте)
.080495E9: B978000000 mov ecx, 000000078 ; количество двойных слов для расшифровки
.080495EE: BBBD03CC09 mov ebx, 009CC03BD ; ключ расшифровки
.080495F3: AD lodsd ; читаем очередной двойное слово <-----+
.080495F4: 33C3 xor eax,ebx ; расшифровываем через xor |
.080495F6: AB stosd ; записываем результат на место |
.080495F7: E2FA loop .0080495F3 ; мотаем цикл -------------------------+
.080495F9: 9D popfd ; восстанавливаем флаги из стека
.080495FA: 61 popad ; восстанавливаем все регистры
.080495FB: BDC0820408 mov ebp, 0080482C0 ; адрес оригинальной точки входа (OEP)
.08049600: FFE5 jmp ebp ; передаем управление расшифрован. коду
Листинг 2. Быстрая расшифровка elf-файла в отладчике gdb
; определяем точку входа в файл
root@5[elf_crypt]#objdump -f elfcrypt-demo
root@5[elf_crypt]# gdb elfcrypt-demo
; ставим точку останова на точку входа
(gdb) b *0x80495DC
; пускаем программу
(gdb) r
; сработала точка останова
; говорим отображать команды Ассемблера
(gdb) display/i $pc
; начинаем трассировать программу
(gdb) si
; продолжаем трассировать
; видим цикл
; ставим точку останова за его концом
(gdb) b *0x80495F9
; запускаем программу «вживую»
(gdb) c
; точка останова достигнута
; программа расшифрована!
Листинг 3. Нет, это не хитрый антиотладочный код, это просто оригинальная точка входа в программу,
еще не расшифрованная расшифровщиком
.text:080482C0 _start proc near
.text:080482C0 8C EE mov esi, gs
.text:080482C2 92 xchg eax, edx
.text:080482C3 80 5C 80 28 F9 sbb byte ptr [eax+eax*4+28h], 0F9h
.text:080482C8 ED in eax, dx
.text:080482C9 57 push edi
.text:080482CA 9E sahf
.text:080482CB 61 popa
.text:080482CC AD lodsd
.text:080482CD 87 C8 xchg ecx, eax
.text:080482CF 01 D5 add ebp, edx
.text:080482D1 B3 4F mov bl, 4Fh
.text:080482D3 0D B5 52 9A 61 or eax, 619A52B5h
.text:080482D8 2D 80 C8 01 55 sub eax, 5501C880h
.text:080482DD CC int 3 ; Trap to Debugger
.text:080482DE 33 F6 xor esi, esi
.text:080482E0 42 inc edx
.text:080482E1 F7 5C 99 E8 neg dword ptr [ecx+ebx*4-18h]
.text:080482E1 _start endp
Листинг 4. Дизассемблерный листинг расшифровщика, внедряемого ELFCrypt в файл (как он выглядит в IDA Pro)
extern:80495DC 7F 01 00 00 extrn puts@@GLIBC_2_0:near
extern:80495E0 FA 00 00 00 extrn __libc_start_main@@GLIBC_2_0:near
extern:80495E4 7F 01 00 00 extrn puts:near ; CODE XREF: .plt:_puts^j
extern:80495E4 ; DATA XREF: .got:off_80495CC↑o
extern:80495E8 FA 00 00 00 extrn __libc_start_main:near
extern:80495E8 ; CODE XREF: ___libc_start_main↑j
extern:80495E8 ; DATA XREF: .got:off_80495D0↑o
extern:80495EC 00 extrn _Jv_RegisterClasses ; weak
extern:80495F0 00 extrn __gmon_start__ ; weak
extern:80495F0 ; DATA XREF: .got:080495D4↑o
Листинг 5. Протокол отладки, иллюстрирующий ход динамической загрузки
; устанавливаем точку останова на начало стартового кода
(gdb) b _start
; запускаем программу на выполнение
(gdb) r
; ок, мы в точке входа. Смотрим на extern
(gdb) x 0x80495DC
; IDA Pro нас уверяет, что extern содержит адрес 0000017Fh, но в действительности область extern
; на момент запуска файла девственно чиста и забита нулями
; незначащие машинные инструкции пропущены
; но вот стартовый код вызывает библиотечную функцию ___libc_start_main, поскольку компилятор
; еще не знает ее фактического адреса, он вставляет переходник к секции .plt,
; содержащей переходники к секции .got, заполняемой динамическим загрузчиком
; IDA Pro корректно отобразила plt-переходник, вызывающий функцию, указатель на которую
; расположен в двойном слове по адресу 80495D0h
; а вот тут уже начались расхождения...
; IDA Pro уверяет, что здесь расположено смещение функции __libc_start_main, в то время как
; отладчик показывает, что здесь находится специальный код push 08h/jmp 8048290h.
; Посмотрим, что покажет IDA Pro по адресу 8048290h
; парад различий продолжается! IDA Pro вообще не показывает ничего! Отладчик же показывает код,
; засылающий в стек смещение первого (считая от нуля) элемента таблицы .got и передающего управление по адресу,
; записанному во втором элементе таблицы .got. Как следует из спецификации elf-формата, первые три элемента секции
; .got зарезервированы для служебных целей и вторая из них хранит адрес функции _dl_map_object_deps, которая,
; получив в качестве аргумента адрес начала .got, читает его содержимое (а содержатся там ссылки на библиотечные функции)
; и заполняет extern фактическими адресами
; ага! Вот эта функция, расположенная на моей машине по адресу 4000BBD0h, принадлежащему библиотеке libc.so.6
; (на других машинах этот адрес может быть иным) она-то и выполняет всю работу по инициализации extern,
; в котором находится наш расшифровщик, уже расшифровавший программу, а затем вызывает __libc_start_main,
; так что загрузка динамической библиотеки происходит совершенно прозрачно
Листинг 6. Распаковка программы путем установки точки останова на _dl_map_object_deps
; загружаем программу в отладчик
root@5[elf_crypt]# gdb elfcrypt-demo
; ставим brkpnt на _dl_map_object_deps
(gdb) hbreak *0x4000BBD0
; запускаем программу
(gdb) r
; первое всплытие установленной точки останова
; сейчас будем проверять - «наше» ли оно или нет
; смотрим стек
(gdb) x $esp+8
; адрес указывает на libc.so.6 это «левое» всплытие, идем дальше
(gdb) c
; второе всплытие установленной точки останова
; проверяем - «наше» ли оно или нет
; должен быть ret из call main
(gdb) x $esp+8
; судя по адресу, это возможно так и есть
; должен быть указатель на main
(gdb) x $esp+0xC
; судя по адресу это так и есть
; проверяем наше предположение
(gdb) disassemble 0x80482e1
; дизассемблер показывает типичный стартовый код, значит, приложение уже распаковано!
Листинг 7. Скрипт для IDA Pro, расшифровывающий программу
auto a,x;
for(a=0x80482C0;a<0x8048338;)
{
x=Dword(a);
x = x ^ 0x9CC03BD;
PatchDword(a,x);
a = a + 4;
}
Листинг 11. Встроенный распаковщик UPX не смог распаковать файл с затертой сигнатурой
root@5[upx-2.01-i386_linux]# ./upx -d elinks
Листинг 12. Снятие дампа с последующей реконструкцией elf-файла
; запускаем упакованный процесс на выполнение
root@5[src]# ./demo
; определяем его pid
root@5[src]# ps -a
; дампим процесс в файл
root@5[src]# ./pd -o dumped 9771
; утилита PD окончила процесс дампинга
; запускаем полученный процесс на выполнение
root@5[src]# ./dumped
Листинг 13. Дизассемблерный листинг единственного антиотладочного приема в Burneye
LOAD:053714A7 mov ebx, 5 ; SIGTRAP
LOAD:053714AC mov ecx, offset anti_handler ; обработчик
LOAD:053714B1 mov edx, 30h ; signal
LOAD:053714B6 mov eax, edx
LOAD:053714B8 int 80h ; signal(SIGTRAP, anti_handler);
LOAD:053714BA add esi, offset word_5375A00
LOAD:053714C0 mov [ebp-2DCh], esi
LOAD:053714C6 int 3 ; Trap to Debugger
LOAD:053714C7 cmp anti_debug, 0 ; если ноль, мы под отладчиком
LOAD:053714CE jnz short debugger_not_present
...
LOAD:05371A0C anti_handler: ; обработчик сигнала SIGTRAP
LOAD:05371A0C push ebp ; (получает управление только
LOAD:05371A0D mov ebp, esp ; при запуске без отладчика)
LOAD:05371A0F inc anti_debug ; увеличиваем секретную переменную
LOAD:05371A15 leave
LOAD:05371A16 retn ; выходим из обработчика
Листинг 14. Фрагмент burndump, отождествляющий упаковщик по «сигнатуре»
codeptr = current->mm->start_code + 1;
/* caller == burneye ??? */
if ((codeptr >> 16) == 0x0537)
printk("<1> 7350 signature 0x0537 found!\n");
Листинг 15. Фрагмент файла, упакованного протектором Burneye
.05371035: FF3508103705 push d,[05371008]
.0537103B: 9C pushfd
.0537103C: 60 pushad
.0537103D: 8B0D00103705 mov ecx,[05371000]
.05371043: E93A000000 jmp .005371082 ---v (1)
-----------------------------------------------------------------------------------------------------------------
Как обнаружить malware-программы?
Универсальный метод
Крис Касперски
Листинг 1. «Макетная» программа va_thread.c, создающая поток тем же самым методом, что и malware
// код потока, который ничего не делает, а только мотает цикл
thread(){while(1);}
main()
{
void *p; // переменная многоцелевого использования
// создаем «честный» поток
CreateThread(0,0,(void*)&thread,0x999,0,&p);
// создаем «нечестный» поток так, как это делает malware
// выделяем блок памяти из кучи, копируем туда
// код потока и вызываем CreateThread
p = VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(p,thread,0x1000);CreateThread(0,0,p,0x666,0,&p);
// ждем нажатия на любую клавишу
getchar();
}
cl.exe va_thread.c
THREAD x va_thread
proclist.exe > out
Листинг 3. Фрагмент кода, ответственный за перечисление всех имеющихся потоков
#include
#include
#include
print_thr(THREADENTRY32 thr)
{
printf("cntUsage : %Xh\n",thr.cntUsage);
printf("th32ThreadID : %Xh\n",thr.th32ThreadID);
printf("th32OwnerProcessID : %Xh\n",thr.th32OwnerProcessID);
printf("tpBasePri : %Xh\n",thr.tpBasePri);
printf("tpDeltaPri : %Xh\n",thr.tpDeltaPri);
printf("dwFlags : %Xh\n",thr.dwFlags);
}
main()
{
HANDLE h; THREADENTRY32 thr; int a;
// создаем «слепок» потоков
h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
// перебираем все потоки один за другим
thr.dwSize = sizeof(THREADENTRY32); a = Thread32First(h, &thr);
if (a && print_thr(thr)) while(Thread32Next(h, &thr)) print_thr(thr);
}
Листинг 4. Фрагмент кода, считывающего значение ESP потока с идентификатором thr.th32ThreadID
HANDLE ht;
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
// преобразуем идентификатор потока в дескриптор
ht = OpenThread(THREAD_GET_CONTEXT, 0, thr.th32ThreadID);
// считываем регистровый контекст
GetThreadContext(ht,&context);
// закрываем дескриптор
CloseHandle(ht);
Листинг 5. Фрагмент кода, определяющий положение дна стека и считывающий байт GET_FZ с его конца
(в которых хранится стартовый адрес потока)
#define GET_FZ 4 // на сколько двойных слов отступать
DWORD buf[GET_FZ];
DWORD x; HANDLE hp;
MEMORY_BASIC_INFORMATION mbi;
// открываем процесс, владеющий данным потоком
hp = OpenProcess(PROCESS_VM_READ|PROCESS_QUERY_INFORMATION,0,thr.th32OwnerProcessID);
// определяем параметры блока памяти, на который указывает регистр ESP
VirtualQueryEx(hp, (void*)context.Esp, &mbi, sizeof(mbi));
// вычисляем положение дна стека
x = (DWORD) mbi.BaseAddress + mbi.RegionSize;
// читаем GET_FZ слов со дна стека в буфер buf
ReadProcessMemory(hp,(char*)x-GET_FZ*sizeof(DWORD),buf,GET_FZ*sizeof(DWORD),&a);
// закрываем дескриптор процесса
CloseHandle(hp);
Листинг 6. Декодирование содержимого буфера buf и определение стартового адреса потока эвристическим методом
DWORD st_adr;
// определяем стартовый адрес потока
st_adr = ((buf[GET_FZ-3])?buf[GET_FZ-3]:buf[GET_FZ-2]);
// выводим стартовый адрес на экран или DEADBEEF, если стартовый адрес определить не удалось
printf("start address : %08Xh\n",st_adr?st_adr:0xDEADBEEF);
// определяем указатель на аргументы потока и выводим его на экран
printf("point to args : %08Xh\n",((buf[GET_FZ-3])?buf[GET_FZ-2]:buf[GET_FZ-1]));
Листинг 7. Фрагмент кода, определяющий тип блока памяти, к которому принадлежит стартовый адрес потока
// определение типа региона памяти, к которому принадлежит стартовый адрес
VirtualQueryEx(hp, (void*)st_adr, &mbi, sizeof(mbi));
// декодирование полученного результата и вывод его на экран
printf("type : %s\n",
(mbi.Type==MEM_IMAGE)?"MEM_IMAGE":
(mbi.Type==MEM_MAPPED)?"MEM_MAPPED":
(mbi.Type==MEM_PRIVATE)?"MEM_PRIVATE":"UNKNOWN");
-----------------------------------------------------------------------------------------------------------------
Ajax. Новое слово в разговоре клиента и сервера
Алексей Мичурин
Test Ajax
header('Content-type: text/xml');
header('Cache-Control: no-cache');
echo date("M d Y H:i:s\n", time());
echo (''.$_SERVER['REQUEST_URI']."\n");
$x=intval($_REQUEST['x']);
$xx=$x*$x;
echo "$x²=$xx\n";
?>
function prepare_http_object() {
r = false;
if (window.XMLHttpRequest) { // Mozilla, Safari, Opera ...
r = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
r = new ActiveXObject("Microsoft.XMLHTTP");
}
return r;
}
function do_http_rq() {
r=prepare_http_object();
if (r) {
setup_http_object(r);
send_http_require(r);
} else {
alert('Эта страница не может быть корректно отображена вашим браузером');
}
}
function prepare_http_object() {
r = false;
if (window.XMLHttpRequest) { // Mozilla, Safari, Opera ...
r = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/xml');
}
} else if (window.ActiveXObject) { // IE
...
obj.onreadystatechange = function_name;
obj.onreadystatechange = function() {
// делаем что-то
}
function setup_http_object(r) {
r.onreadystatechange = function() {process_response(r);};
}
function unclose(r) {
r.onreadystatechange = function() {};
}
obj.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
r.open('GET', 'calc.php?x='+escape(document.frm.x.value), true);
/ajax/calc.php?x=4
-----------------------------------------------------------------------------------------------------------------
Устанавливаем DACS
Сергей Яремчук
$ cd openssl-0.9.8a/
$./config --prefix=/opt/openssl
$ make; make test
# make install
$ cd apache-2.0.58
$./configure --enable-ssl --with-ssl=/opt/openssl --prefix=/opt/apache2
# /opt/apache2/bin/apachectl –l
# /opt/openssl/bin/openssl req -config /opt/openssl/openssl.cnf -new -x509 -keyout gw-ca.pem -out gw-ca.pem -days 365
# /opt/bin/openssl rsa -in gw-ca.pem -out gw-ca.key
# /opt/ openssl/bin/openssl x509 -in gw-ca.pem -out gw-ca.crt
# cp gw-ca.crt /opt/apache2/conf/server.crt
# cp gw-ca.key /opt/apache2/conf/server.key
Include /opt/conf/ssl.conf
SSLCertificateFile /opt/apache2/conf/ssl.crt/server.crt
SSLCertificateKeyFile /opt/apache2/conf/ssl.key/server.key
$ cd expat-2.0.0
$ ./configure --prefix=/opt/expat; make
# make install
# /sbin/ldconfig
$ cd dacs-1.4.13a
$ src/configure --help
$ src/configure --with-ssl=/opt/openssl --with-expat=/opt/expat --with-apache=/opt/apache2 --enable-unix-auth --enable-debug --enable-apache-auth --enable-native-auth --prefix=/opt/dacs --enable-ndbm=no --enable-bdb=no
$ gmake depend
$ gmake smalltag
# gmake install
# /opt/dacs/bin/version -v
# cat httpd.conf | grep LoadModule
# /opt/apache2/bin/apachectl start
# /opt/dacs/bin/sslclient testserver.net:443
Options Indexes FollowSymLinks
Order allow,deny
Allow from all
# Настраиваем виртуальный сервер и делаем доступными каталоги DACS
NameVirtualHost 127.0.0.1:8080
Listen 127.0.0.1:8080
ServerName testdacs.net
DocumentRoot "/opt/dacs/www/"
ErrorLog "/opt/dacs/logs/error_log"
TransferLog "/opt/dacs/logs/access_log"
ScriptAlias /cgi-bin/ "/opt/apache2/cgi-bin/dacs/"
Alias /css "/opt/dacs/www/css/"
Alias /icons/ "/opt/apache2/icons/"
Alias /dacs "/opt/dacs/www/"
Alias /dtd-xsd "/opt/dacs/www/dtd-xsd/"
Alias /examples "/opt/dacs/www/examples/"
Alias /handlers "/opt/dacs/www/handlers/"
Alias /man "/opt/dacs/www/man/"
Alias /misc "/opt/dacs/www/misc/"
Alias /mod "/opt/dacs/www/mod/"
# install -g apache2 -m 0640 /opt/dacs/federations/site.conf-std /opt/dacs/federations/site.conf
${Conf::FEDERATIONS_ROOT}/${Conf::FEDERATION_DOMAIN}/${Conf::JURISDICTION_NAME}
# install -g apache2 -m 0660 /dev/null /opt/dacs/federations/dacs.conf
# install -d -g apache2 -m 0770 /opt/dacs/federations/testdacs.net/
# install -d -g apache2 -m 0770 /opt/dacs/federations/testdacs.net/FIRST
# install -d -g apache2 -m 0770 /opt/dacs/federations/testdacs.net/FIRST/acls
# install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/FIRST/acls/revocations
# install -d -g apache2 -m 0770 /opt/dacs/federations/testdacs.net/FIRST/groups /opt/dacs/federations/testdacs.net/FIRST/groups/FIRST /opt/dacs/federations/testdacs.net/FIRST/groups/DACS
# install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/FIRST/groups/DACS/jurisdictions.grp
FEDERATION_DOMAIN "testdacs.net"
FEDERATION_NAME "DACSTEST"
LOG_LEVEL "info"
JURISDICTION_NAME "FIRST"
# ln -s /opt/dacs/federations/dacs.conf /opt/dacs/federations/ testdacs.net/FIRST/dacs.conf
# /opt/dacs/bin/conf -u testdacs.net -q
# install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/federation_keyfile
# /opt/dacs/bin/mkkey -u testdacs.net -q /opt/dacs/federations/testdacs.net/federation_keyfile
# cat /opt/dacs/federations/testdacs.net/federation_keyfile
# install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/FIRST/jurisdiction_keyfile
# /opt/dacs/bin/mkkey -uj FIRST /opt/dacs/federations/testdacs.net/FIRST/jurisdiction_keyfile
dacs_admin()
# install -g apache2 -m 0660 /dev/null /opt/dacs/federations/FIRST/acls/acl-prenv.0
user("any") # то есть всем
AddDACSAuth dacs-acs /opt/dacs/bin/dacs_acs "-t -v"
SetDACSAuthMethod dacs-acs external
SetDACSAuthConf dacs-acs "/opt/dacs/federations/dacs.conf"
AllowOverride AuthConfig
Require valid-user
Options ExecCGI
AuthType DACS
AuthDACS dacs-acs
# /opt/apache2/bin/apachectl restart
JURISDICTION_NAME "FIRST"
URL "http://testdacs.net:8080/cgi-bin/dacs/local_unix_authenticate"
STYLE "pass"
CONTROL "sufficient"
# install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/FIRST/passwd
# /opt/dacs/bin/dacspasswd -u testdacs.net -q -a sergej
# cat /opt/dacs/federations/testdacs.net/FIRST/passwd
# /opt/dacs/bin/cookie -u testdacs.net -decrypt < cookie
-----------------------------------------------------------------------------------------------------------------
Развиваем модуль DBI
Алексей Мичурин
# для DBI это не работает
@ISA=qw(DBI);
my $dbh=DBI->connect(...);
my $sth=$dbh->prepare('select ...');
1: package DBItoo;
2: use strict;
3: use DBI;
4: use vars qw(@ISA);
5: @ISA = qw(DBI);
6: package DBItoo::db;
7: use vars qw(@ISA);
8: @ISA = qw(DBI::db);
9: package DBItoo::st;
10: use vars qw(@ISA);
11: @ISA = qw(DBI::st);
12: 1;
#!/usr/bin/perl -w
use strict;
use DBItoo;
my $dbh=DBItoo->connect('DBI:mysql:test', 'root', '');
my $sth=$dbh->prepare('SELECT id, txt FROM tbl');
$sth->execute();
while (my ($id, $txt)=$sth->fetchrow_array()) {
print "$id $txt\n";
}
$sth->finish();
$dbh->disconnect();
use DBI;
my $dbh=DBI->connect('DBI:mysql:test', 'root', '', {RootClass => 'DBItoo'});
3: use DBI
@DBItoo_cmpct::ISA = qw(DBI);
@DBItoo_cmpct::db::ISA = qw(DBI::db);
@DBItoo_cmpct::st::ISA = qw(DBI::st);
1;
$dbh=DBI->connect(...);
1: use strict;
2: @DBIru::ISA = qw(DBI);
3: @DBIru::st::ISA = qw(DBI::st);
4:
5: package DBIru::db;
6: @DBIru::db::ISA = qw(DBI::db);
7: sub connected {
8: my ($dbh, $src, $login, $passwd, $attr)=@_;
9: $dbh->do('SET CHARACTER SET koi8r');
10: }
11:
12: 1;
$dbh->do(q|SET time_zone='+04:00'|);
[dbi_options]
default-character-set=koi8r
$db=DBI->connect('DBI:mysql:test;'.
'mysql_read_default_file=/home/etc/my.cfg;'.
'mysql_read_default_group=dbi_options',
'root', '');
mysql> SET GLOBAL time_zone = '+04:00';
1: use strict;
2: @DBIping::ISA = qw(DBI);
3: @DBIping::st::ISA = qw(DBI::st);
4:
5: package DBIping::db;
6: @DBIping::db::ISA = qw(DBI::db);
7: sub ping {
8: my ($dbh)=@_;
9: my $r=0;
10: eval {
11: local $SIG{__DIE__} = sub { return (0); };
12: local $SIG{__WARN__} = sub { return (0); };
13: $r=$dbh->do('select 1');
14: };
15: return ($@)?0:$r;
16: }
17: 1;
1: use strict;
2: @DBIlog::ISA = qw(DBI);
3: @DBIlog::db::ISA = qw(DBI::db);
4:
5: package DBIlog::st;
6: @DBIlog::st::ISA = qw(DBI::st);
7: sub execute {
8: my $st=shift;
9: my @args=@_;
10: my $s=$st->{'Statement'};
11: $s=~s/\s+/ /g;
12: open FH, '>>statments' or die;
13: print FH "$s\n";
14: close FH;
15: return $st->SUPER::execute(@args);
16: }
17: 1;
1: use strict;
2: @DBItime::ISA = qw(DBI);
3: @DBItime::db::ISA = qw(DBI::db);
4:
5: package DBItime::st;
6: @DBItime::st::ISA = qw(DBI::st);
7: sub execute {
8: my $st=shift;
9: my $s=$st->SUPER::execute(@_);
10: $st->{execure_at => time()} if ($s);
11: return $s;
12: }
13: 1;
1: use strict;
2: @DBImd5::ISA = qw(DBI);
3: @DBImd5::st::ISA = qw(DBI::st);
4:
5: package DBImd5::db;
6: @DBImd5::db::ISA = qw(DBI::db);
7: sub md5 {
8: my ($db, $table)=@_;
9: my $sql='CHECKSUM TABLE '.
10: $db->quote_identifier($table);
11: my $st=$db->prepare($sql);
12: $st->execute();
13: my (undef, $md5)=$st->fetchrow_array();
14: $st->finish();
15: return $md5;
16: }
17: 1;
$dbh->md5(имя_таблицы);
1: use strict;
2: @DBIautodef::ISA = qw(DBI);
3: @DBIautodef::db::ISA = qw(DBI::db);
4:
5: package DBIautodef::st;
6: @DBIautodef::st::ISA = qw(DBI::st);
7: sub fetchrow_array {
8: my $st=shift;
9: return map {defined($_)?$_:'N/A'} ?
$st->SUPER::fetchrow_array();
10: }
11: 1;