$ses::auth->{trust} or Error('З'єднання не довірене. Необхідно перелогінитися');
До клієнтської статистики може потрапити не тільки клієнт, а й адміністратор від його імені, тому в деяких випадках бажано виводити різну інформацію для адміна та клієнта, а також фіксувати, що саме адміністратор виконав дію:
if( 1 + 1 > 3 )
{
Error( Adm->id? 'Паніка! Perl неправильно вважає' : 'Сервіс тимчасово недоступний');
}
# Поповнимо рахунок клієнта, при цьому Pay_to_DB сама проставит автора
Pay_to_DB(uid=>$uid, cash=>10, category=>1);
====== POST/GET параметри ======
Отримати параметри, надіслані через браузер, можна за допомогою ses::input:
http://xxx/?a=test&b=0&uid=33
if( ses::input('a') eq 'test' && ses::input_exists('b') )
{
# Умова спрацює т.к. в url a = test і параметр b присутній
# Параметр uid про всяк випадок примусово приведемо до цілого числа
my $uid = ses::input_int('uid');
$uid or Error('Введіть ціле число, що не дорівнює нулю');
}
Хеш усіх переданих параметрів зберігається в $ ses:: input_orig:
# Якщо параметр yes не існує або не встановлено,
# відредагуємо самі на себе і пошлемо всі параметри + встановимо yes
ses::input('yes') or url->redirect( { %$ses::input_orig, yes=>1 } );
Існує альтернативний спосіб передачі параметрів - дані записуються в базу даних таблицю [[Db_tables#webses_data|webses_data]], доступ до яких здійснюється за ключом unikey таблиці.
Взагалі через дану таблицю можуть передаватися будь-які дані, а передача параметрів від браузера - одна з фіч. На прикладі покажемо навіщо потрібний такий механізм.
Припустимо, клієнт надсилає дані. Модуль їх перевіряє. Знаходить помилку. Якщо вивести помилку, клієнт буде роздратований тим, що ввів багато даних і йому знову знадобиться їх вводити. Тому передані дані записуються в webses_data і відбувається редирект на сторінку введення, при цьому параметр _unikey встановлюється значення поля unikey збережених даних.
Перед завантаженням модуля, якщо calls.pm бачить параметр _unikey, він автоматично витягує з БД зв'язану з ключем рядок і дешифрує її змінну $ses::data. Далі, якщо існує ключ $ses::data->{-input}, то calls.pm «дає вигляд», що браузер надіслав POST/GET дані, що знаходяться $ses::data->{-input}.
Найчастіше ці події відбуваються прозоро, тобто. не потрібно думати про ключ -input. Наприклад, редирект завжди здійснюється через webses_data:
$Url->redirect(a=>'main', uid=>15);
В даному випадку відбудеться запис {a=>'main', uid=>15} у webses_data, після чого відбудеться перехід http::%%//%%xxx/?_unikey=yyyyyy. Тут yyyyyy – ключ до даних, записаних у таблицю.
Якщо ми вже заговорили про редирект, то відзначимо 2 корисні його параметри -made і -error. Перший призначений для того, щоб вивести повідомлення вгорі сторінки після редиректу, при цьому якщо буде встановлено -error, то червоним кольором:
$Url->redirect(a=>'main', -error=>1,
-made=>'Помилкова операція. Редиректимося на титульну сторінку ');
====== Підпрограми модуля main ======
ToLeft, ToRight, ToTop
Виводять дані в ліву, праву і відповідно у верхню частину html-сторінки, що формується.
ToLeft 'Текст зліва';
**MessageBox** виводить повідомлення у рамці
ToLeft MessageBox('Повідомлення 1');
ToRight MessageBox('Повідомлення 2');
**MessageWideBox** виводить повідомлення у рамці, розтягнутій по ширині
Show Message
WideBox('Повідомлення');
**Box** виводить темплейт box.html. Усі параметри необов'язкові
* title - заголовок повідомлення
* msg - повідомлення
* wide - якщо встановлений, то рамка розтягується по ширині
* css_class - css class повідомлення
Show Box(
title => 'Заголовок',
wide => 1,
msg => 'Текст повідомлення всередині рамки',
css_class => 'error txtpadding',
);
**WideBox** теж, що й Box, але параметр wide встановлений в 1
Show WideBox();
**Menu**
Menu теж, що і MessageWideBox, але повідомлення має css class `navmenu`, що наказує виводити гіперпосилання на всю ширину блоку, одне під одним.
ToLeft Menu(
url->a( 'Список клієнтів', a=>'users' ).
url->a( 'Статистика трафіку', a=>'traf_log' ).
url->a( 'Google', -base=>'http://google.com' )
);
**Center** виводить інформацію відцентрованої по горизонталі
Show Center MessageBox('Center');
Відмінність від css h_center у цьому, що дозволяє центрувати як текст.
**Error** виводить повідомлення про помилку та завершує виконання скриптів
1 > 2 && Error('1 > 2 !!!');
**Error_** теж, що й Error, але повідомлення обробляється підпрограмою %%_(%%)
$lang::hello_msg = 'Здрастуйте [filtr|bold], на вашому рахунку [bold] $';
Error_($lang::hello_msg, 'адміністратор', 1000);
**ErrorMess** теж, що й Error, але виконання скрипту не припиняється
ErrorMess('Щось не так!');
Error('Точно щось не так...');
===== Pay_to_DB =====
**Pay_to_DB** створює запис у таблиці pays за вхідними параметрами:
* uid - id клієнта, з яким пов'язана запис чи 0, а то й пов'язана. Необов'язковий параметр за промовчанням 0.
* cash – сума, або 0, якщо платіж не фінансовий. Необов'язковий параметр за промовчанням 0.
* reason - поле reason. Необов'язковий параметр.
* comment – поле comment. Необов'язковий параметр.
* time - timestamp платежу. Необов'язковий параметр за промовчанням поточний час.
* category - категорія. Обов'язковий параметр.
Повертає 1 у разі успішного запису. У параметрах запису автоматично встановлюється автор адмін або клієнт залежно від авторизованого. Також встановлюється IP.
\\ Якщо запис фінансовий, то має бути виконаний у транзакції, наприклад:
Db->begin_work або Error($lang::err_try_again);
my $rows1 = Db->do("UPDATE users SET balance=balance+(?) WHERE id=?", $money, $uid);
my $rows2 = Pay_to_DB(uid=>$uid, cash=>$money, category=>1);
if( $rows1 < 1 || $rows2 < 1 || !Db->commit )
{
Db->rollback;
Error($lang::err_try_again);
}
Тут Db->begin_work перемикає Db на режим транзакцій. Починаючи з цього моменту, sql update/insert будуть виконуватися, але не фіксуватися в БД поки не буде виконаний Db->commit. У разі перевіряється, що обидва запити було виконано успішно, тобто. якщо хоча б один із запитів повернув менше одиниці - виконується відкат Db->rollback. Відкат гарантує, що жоден із запитів не буде зафіксовано у БД. Також він вимикає режим транзакцій.
===== Get_usr_info =====
Отримує дані клієнта щодо його id. У разі успіху повертає посилання на хеш з даними, інакше повідомлення про помилку.
my $ info = Get_usr_info(15);
ref $info або Error $info;
Show 'ПІБ клієнта з id=15: '.v::filtr($info->{fio});
Підпрограма повертає як основні дані, а й додаткові поля, і навіть список ip, які належать клієнту.
debug('pre', $info);
===== _() =====
Підпрограма, що складається з одного символу підкреслення, вставляє в заданий рядок параметри:
Show _('[div][p h_center][div bold h_right]', 'Текст1', 'Текст2', 'Текст3');
Перетворюється на:
Текст1Текст2
Текст3
Як видно, квадратні дужки вказують на вставку чергового параметра у поточне місце. При цьому перше слово у квадратних дужках вказує на тег. Є кілька зарезервованих слів, які не вказують на тег, наприклад, filtr - ескейпити html-спецсимволи в параметрі. trim – видаляє прогалини по краях параметра. Крім того, вертикальна характеристика дозволяє вставляти кілька керуючих послідовностей:
Show _('Ви ввели [filtr|trim|span bold]', 'xxx');
Перетворюється на рядок «Ви ввели xxx»
====== Таблиці ======
perl код
# Створюємо таблицю
my $tbl = tbl->new(-class=>'td_wide');
# Перший рядок
$tbl->add( '*', 'lll', 'комірка 1', 'комірка 2', 'комірка 3' );
# Другий рядок
$tbl->add( '*', 'lll', 'комірка 1', 'комірка 2', 'комірка 3' );
# Виводимо таблицю
Show $tbl->show;
Методом new створюється нова порожня таблиця. Вхідні параметри:
-class : css class таблиці
-row1 : css class першого ряду
-row2 : css class другого ряду
Параметри не є обов'язковими. Можуть бути взяті з іншого:
perl код
my $tbl1 = tbl->new( -class=>'td_wide td_ok' );
# Class для таблиці 2 буде 'td_wide td_ok'
my $tbl2 = $tb1->new(-row1=>'row5');
Приклади класів для таблиць
td_wide : таблиця максимальної ширини
fade_border : осередки відокремлюються напівпрозорими лініями
pretty : якщо в таблиці буде мало рядків, то вони будуть більшими за висотою
td_ok : оптимальний паддинг для осередків таблиці
td_tall : високі рядки
td_medium : рядки середньої висоти
td_wide : широкі осередки
td_narrow : вузькі осередки
Рядки додаються методами add (наприкінці таблиці) і ins (на початок таблиці.). Формат параметрів:
* css ряду, що вставляється
* рядок - карта осередків
* осередок 1
* осередок 2
* ...
Якщо в css буде символ зірочка - це вказівка дати ряду css з параметра -row1, після чого значення в -row1 і -row2 обміняються місцями. У такий спосіб можна організувати «зебру».
Карта осередків - це рядок, який описує вирівнювання кожного осередку:
l : вирівнювання по лівому краю
r : з правого
c : по центру
L : по лівому та 2 осередки об'єднуються в один
R : праворуч і 2 осередки об'єднуються в одну
C : по центру та 2 осередки об'єднуються в один
E : по лівому та 3 осередки об'єднуються в один
3 : по центру та 3 осередки об'єднуються в один
4 : по центру та 4 осередки об'єднуються в один
..
9: по центру та 9 осередків об'єднуються в одну
t : по центру та вертикальне вирівнювання top
T : 2 осередки в одну, по центру та вертикальне вирівнювання top
пробіл : порожній осередок
perl код
my $tbl = tbl->new( -class=>'td_wide td_ok' );
$tbl->add( '*', 'rcl', 'рівняння праворуч', 'центр', 'ліво');
$tbl->add( '*', 'rL', 'текст у 1й комірці', 'комірка 2 і 3 об'єднана в 1');
$tbl->add( '*', '3', 'текст центром і всі осередки об'єднані в одну');
Show $tbl->show;
Якщо будь-яка комірка буде у квадратних дужках - це відключить фільтрацію html-спецсимволів. Якщо ви відображаєте дані, надіслані клієнтом, ви не повинні відключати фільтрацію.
perl код
$tbl->add( '*', 'rl', 'ви надіслали рядок', ses::input('str'));
$tbl->add( '*', 'rl', 'поле введення', [ v::input_t(name=>'str') ]));
Автоматично ведеться облік рядків та стовпців таблиці. Метод rows дозволяє отримати поточну кількість рядів. Якщо при вставці рядків з'ясовується, що осередок менше ніж у попередньому, то йде автоматичне розширення останнього шляхом об'єднання з рештою:
perl код
$tbl->add( '*', 'll', 'Здрастуйте', 'Станіслав');
осередок буде з'єднаний з останньою т.к. у попередньому рядку 2 стовпці
$tbl->add( '*', 'l', 'сьогодні все ок');
# return не спрацює т.к. у таблиці 2 рядки
$tbl->rows < 1 && return;
**Альтернативний спосіб вставки рядків** дозволяє надавати css клас персонально кожному осередку (а не тільки всьому рядку в цілому). Крім того, для кожного осередку вказується заголовок. Кожен рядок необхідно обернути у квадратні дужки:
perl код
$tbl->add( '*', [
[ 'bold h_left', 'Заголовок 1й колонки', 'Увага' ],
[ 'h_right', 'Заголовок 2й колонки', 'всім' ],
]);
У результаті буде вставлено рядок із двома осередками: у першому вирівнювання по лівому краю, у другій - по правому. У лівій виділений (клас bold) текст «Увага», у правій текст «усім». Коли таблиця буде виведена, то її шапці у першому осередку буде текст «Заголовок 1й колонки», у 2й - «Заголовок 2й колонки».
\\ \\ ====== Package Url ======
Призначений на формування гіперпосилань.
Методи
new : створення нового об'єкту
a : рендеринг url-об'єкта в гіперпосилання
post_a : рендеринг у гіперпосилання, при натисканні на яке
дані будуть надіслані post-методом
form : рендеринг url-об'єкта у форму
url: отримання url з об'єкта
redirect: редирект
Якщо параметр **не** починається зі знака тире – це параметр url-а:
perl код
my $url = url->new( a=>1, b=>2, -class=>'nav', -style=>'color:#000' );
Show $url->a('Текст посилання');
Буде перетворено на Текст посилання
Одне посилання можна створити на основі іншого, можна перевизначати параметри і т.д.
perl код
my $url = url->new( a=>1, b=>2, -class=>'nav', -style=>'color:#000' );
my $ url2 = url-> new (b => 3); #?a=1&b=3
$url2->{a} = 'demo'; #?a=demo&b=3
Show $url2->a('OK', b=>4); #?a=demo&b=4
$url->{b} = undef;
Show $url2->a('OK'); #?a=demo
У всіх параметрах ескейп html-спецсимволи. Квадратні дужки відключають це, найчастіше необхідно для тексту посилання:
perl код
my $url = url->new(-class=>'nav');
Але краще це зробити через стиль або клас
Show $url->a( [ 'Bold text' ] );
У формах порядок параметрів відрізняється від гіперпосилання, спочатку параметри, потім вміст форми:
perl код
my $form = _('[p][p h_center][p h_center]',
'Введіть ціле позитивне число:',
v::input_t(name=>'num'),
v::submit('Далі')
);
my $form = $Url->form(
a=>'module_name', param2=>'test', $form
);
Параметр -ajax автоматично конвертується на -class='ajax'. При цьому JS NoDeny усі посилання, у яких присутній такий клас, робить «аяксовими» - при натисканні на такі посилання не завантажується нова сторінка, але йде http-запит на сервер, а відповідь обробляється скриптом nody.js у браузері.
\\ \\ ====== Package Db ======
Призначений для роботи з базою даних. Основний метод – sql.
2 формати виклику
* Db->sql(sql, параметри для плейсхолдерів)
* Db->sql%%({%% параметри})
Якщо необхідна вибірка лише одного рядка:
my %p = Db->line(параметри);
Хеш %p порожній якщо
* Порожня вибірка
* сталася помилка (невірний sql, дисконнект БД,...)
Щоб уточнити: DB->ok повертає 1, якщо не було помилок.
Вибір одного рядка
my %p = Db->line("SELECT * FROM users WHERE id=? AND grp=?", $id, $grp);
Show %p? "$p{name}, $p{fio}" : Db->ok? 'порожня вибірка' : 'внутрішня помилка';
Вибірка кількох рядків
my $db = Db->sql("SELECT id, name FROM users WHERE field=?", $unfiltered_field);
while( my %p = $db->line )
{
Show "$p{id} = $p{name}
";
}
Вибір декількох рядків з іншим форматом виклику
my $db = Db->sql(
sql => "SELECT * FROM tbl WHERE field=? AND val=?",
param => [ $filed, $val ],
comment => 'Вибірка номер 2',
);
while( my %p = $db->line ) { ... }
UPDATE/INSERT
my $rows = Db->do("UPDATE websessions SET uid=?, role=? WHERE ses=? LIMIT 1", $id, $role, $ses);
$rows>0 or Error('Помилка!'); не робіть $rows or Error() т.к. rows може = -1
Виконання кількох запитів у транзакції
Db-> do_all (
[$sql1, $param1, $param2 ],
[$sql2, $param3 ],
);
Перевіряється, що кожен запит торкнувся як мінімум 1 рядка. Увага! Якщо запит виконався, але не торкнувся жодного рядка (жоден збіг за умовою WHERE), то буде відкат транзакції.
Додаткові методи
* disconnect - розриває з'єднання з БД
* connect - здійснює з'єднання з БД
* begin_work - старт транзакції
* commit - коміт транзакції
* rollback - відкат транзакції
* ok - чи був успішний останній виконаний sql
* rows - рядків торкнувся останній виконаний sql
* filtr - екранування небезпечних символів sql