Errors Output
  1. errors compiling global.asa: Errno architecture (x86_64-linux-thread-multi-3.10.0-957.1.3.el7.x86_64) does not match executable architecture (x86_64-linux-thread-multi-3.10.0-693.17.1.el7.x86_64) at /usr/lib64/perl5/Errno.pm line 11. at /usr/lib64/perl5/Errno.pm line 11. require Errno.pm called at /usr/lib64/perl5/IO/Socket.pm line 18 IO::Socket::BEGIN() called at /usr/lib64/perl5/Errno.pm line 0 eval {...} called at /usr/lib64/perl5/Errno.pm line 0 require IO/Socket.pm called at /usr/share/perl5/Net/SMTP.pm line 15 Net::SMTP::BEGIN() called at /usr/lib64/perl5/Errno.pm line 0 eval {...} called at /usr/lib64/perl5/Errno.pm line 0 require Net/SMTP.pm called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax::BEGIN() called at /usr/lib64/perl5/Errno.pm line 0 eval {...} called at /usr/lib64/perl5/Errno.pm line 0 eval ' #line 1 /var/www/HDD2/mc.arhcity.ru/asa/global.asa package Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax; ;; use strict ;; use vars qw($Application $Session $Response $Server $Request); ;; use lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; #!/usr/bin/perl use Time::HiRes qw(gettimeofday tv_interval); use Apache::DBI; # automatic persistent database connections use DBI; use HTTP::Date; use Digest::SHA1 qw(sha1_hex sha1_base64); use Socket; use URI::UTF8::Punycode; use APR::UUID; use Text::Iconv; use Net::SMTP; # when PerlSetVar UseStrict setting on, need to declare # global variables with "use vars" ################################################################## # declare global variables use vars (\'$db\', # database interface \'$FORM\', # form data, method POST \'$QUERY\', # form data, method GET \'$POST\', # unformat form data, method POST \'$SERVER\', # server variables \'$localnet\', # access from local network \'$have_inet\', # access to internet \'$remoteaddr\', # remote IP address \'$useragent\', # UserAgent () \'$site_admin\', # Enable extra functions for site admins \'$logged_in\', # admin access by session \'$lc_logged_in\', # private cabinet access by session \'$servername\', # name of server \'$addrubrics\', # additional menu "rubrics" \'$tpl_dir\', # html template directory \'$godaccess\', # GOD access \'$hires_time\', # time generation of page ############################# \'%userinfo\', # entrie user data (hash) \'%section\', # entrie section data (hash) \'%document\', # entrie document data (hash) ############################# \'@treewalk\', # walking from leaf to root = ([$node, $secname, $sectpl]) \'%mod_params\', # parameters for plugins \'$zx_counter\', # counter for all unique repitable operations \'$site_url\', # url to site \'$site_path\', # path to site location \'$blindview\', # blind vew mode \'%CSS_vars\', # CSS variables ); ################################################################## my $host = \'localhost\'; my $db_name = \'ipcms3\'; my $dsn = "DBI:mysql:database=$db_name:host=$host"; my $username = \'root\'; my $password = \'\'; ################################################################## my $log_file; my $uploaddir; my $admin_dir = "/admin/"; my $lcab = "/lc/"; # list of datastore fields for separate \'_ex\' and non \'_ex\' fields my @doc_fields = qw(sid pid userid url pagename pagebody pagedate pagemodify pageorder sh_hdr sh_dir sh_nav sh_tab docstatus rating1 rating2); # at the begining of the page execution sub Script_OnStart { $hires_time = [gettimeofday]; $Response->Include("site_setup.asp"); # get default values for current site $log_file = "$site_path/datafiles/ipcms3.log"; $uploaddir = "$site_path/asp/data"; $Response->{\'ContentType\'} = "text/html"; $Response->{\'Charset\'} = "Windows-1251"; # $Response->{\'Expires\'} = 0; # page expired after NN seconds from download. # $Response->{\'Last-Modified:\'} = time2str(time-1); $FORM = $Request->Form(); $QUERY = $Request->QueryString(); # $POST = $Request->BinaryRead($Request->ServerVariables(\'CONTENT_LENGTH\')); # for debug $SERVER = $Request->ServerVariables(); $remoteaddr = $SERVER->{\'REMOTE_ADDR\'}; $servername = $SERVER->{\'SERVER_NAME\'}; $tpl_dir = $SERVER->{\'DOCUMENT_ROOT\'}."/templates"; $blindview = get_cookie("blindview") || 0; %userinfo = (); %section = (); %document = (); $addrubrics = \'\'; $site_admin = 0; $logged_in = 0; $godaccess = 0; $localnet = 0; $have_inet = 0; @treewalk = (); $zx_counter = 0; # Global Redirect Block... if ($servername eq \'arhcity.ru\') { $Response->Redirect("http://$site_url"); } if ($servername eq \'arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } if ($servername eq \'www.arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } # if ($SERVER->{HTTPS} ne \'on\') { # $Response->Redirect("https://www.arhcity.ru/?$SERVER->{QUERY_STRING}"); # } my $ic = Text::Iconv->new("UTF-8", "WINDOWS-1251"); my @r = (); foreach my $i (split(/\\./, $servername)) { if ($i =~ m/^xn--/) { push(@r, puny_dec($i)); } else { push(@r, $i); } } $servername = join(\'.\', @r); $servername = $ic->convert($servername); if ($SERVER->{HTTP_USER_AGENT} =~ m/edge/i) { $useragent = \'edge\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/chrome/i) { $useragent = \'chrome\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/webkit/i) { $useragent = \'safari\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/opera/i) { $useragent = \'opera\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/msie/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/trident/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/mozilla/i) { $useragent = \'mozilla\' } else { $useragent = \'unknown\'; } if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { # read CSS color variables for replace in html code (MSIE/Edge not support CSS vars); my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $CSS_vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); } if (($remoteaddr =~ m/^192\\.168\\./) || ($remoteaddr eq \'212.14.176.38\') || ($remoteaddr eq \'212.14.176.39\') || ($remoteaddr eq \'212.14.176.46\') || ($remoteaddr eq \'212.14.176.40\') || ($remoteaddr eq \'212.14.176.41\') || ($remoteaddr eq \'212.14.176.44\') || ($remoteaddr eq \'195.239.119.234\') # Городской центр гражданской защиты ) { $localnet = 1; } if (($localnet) && ( # Enable extra functions for site admins ($remoteaddr eq \'192.168.1.84\') || # GaidukAV ($remoteaddr eq \'192.168.1.44\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.45\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.46\' ) || # KorzhevDP ($remoteaddr eq \'192.168.51.144\') || # VishnyakovNS ($remoteaddr eq \'192.168.1.102\') || # EkimovKS v.1 ($remoteaddr eq \'192.168.1.110\') || # EkimovKS v.2 ($remoteaddr eq \'192.168.51.42\')) # EkimovKS v.3 ) { $site_admin = 1; } # connect to database $db = DBI->connect($dsn, $username, $password); if (! $db) { print "<p>Database server not responding.<br>Try later.</p>\\n"; $Response->End(); } # ONLY FOR RUSSIAN for MySQL !!! $db->do("set names cp1251"); if ($localnet) { # enable/disable outside scripts on site for local users without inet. ($have_inet) = getonerec("select count(ip) from squid_list where ip = \'$remoteaddr\'"); } else { $have_inet = 1; } # ------------------------------------------------------------ # $have_inet = 0; # !!! disable external scripts on site !!! # ------------------------------------------------------------ if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # !!! admin mode !!! $logged_in = 0; my $uname = $Session->{Authentication}; my $topframe = 0; if ($uname) { # logged in $logged_in = 1; $Session->{top_frame} = 0; my $adm_lib = $admin_dir . "lib/"; if ($SERVER->{\'REQUEST_URI\'} =~ m/$adm_lib/) { # read user info %userinfo = get_user_info($uname); $godaccess = 1 if ($userinfo{god} eq \'Y\'); if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no header } else { $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; } if ($SERVER->{\'REQUEST_URI\'} =~ m/(section.asp)|(page.asp)|(journal.asp)|(admin.asp)/i) { $Response->Include("page_autologoff.asp"); } } } else { # not logged in $topframe = $Session->{top_frame}; if (!$topframe) { my $location = "top.location.href=\'/admin/?t=".time()."\'"; print qq{<script>$location</script>}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n</body>\\n</html>\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with <style></style> definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "<pre>",Dumper(@_),"</pre>\\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n<script>\\n$location\\n</script".">\\n"; } ###################################################################### sub navigator { # отобразить навигатор (путь с корня до страницы) my @a = (\'<a href="/">Начало</a>\'); # if $sid in internal section (#6) - don\'t show any information my $rootsec = @treewalk[$#treewalk]; if ( (!$localnet) && ($rootsec->[0] == 6) ) { # ... } else { foreach my $i (reverse @treewalk) { push(@a, qq{<a href="/?page=$i->[0]/0">$i->[1]</a>}) if ($i->[0] > 0); } } return join(\' <span style="color:red"><img src="/pic/navar.gif" align="baseline"></span> \', @a); } ###################################################################### sub get_config_value { my $varname = shift; my ($varvalue) = getonerec("select varvalue from options where varname = \'$varname\'"); return $varvalue; } ###################################################################### sub store_config_value { my ($varname, $varvalue) = @_; my $query = "update options set varvalue=? where varname=?"; my $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($varvalue, $varname) || print $db->errstr, ", query:[$query]<br>\\n"; $st->finish; } ###################################################################### sub get_user_info { # прочитать информацию о зарегистрированном пользователе (по логину) # return hash my $user = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where username = \'$user\'"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub get_user_id_info { # прочитать информацию о зарегистрированном пользователе (по id) # return hash my $user_id = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where id = $user_id"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub make_pw_hash { # (password) # Создание уникального хэша по паролю my $password = shift; my $letts = \'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\'; my $lettl = length($letts); my $salt = \'\'; $password = substr($password, 0, 32) if (length($password) > 32); # limit password length for my $i (1 .. 5) { $salt .= substr($letts, int(rand() * $lettl), 1); } return $salt.sha1_base64($salt.$password); } ###################################################################### sub check_pw_hash { # (password, pwd_hash) # проверка на соответствие хэша и пароля my $password = shift; my $pw_hash = shift; my $salt = substr($pw_hash, 0, 5); $password = substr($password, 0, 32) if (length($password) > 32); # limit password length return (substr($pw_hash, 5) eq sha1_base64($salt.$password)); } ###################################################################### sub check_auth { # (user, password) # проверка авторизации my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'N\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub check_auth_lc { # (user, password) # проверка авторизации lcab my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'Y\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub get_inherit_tpl { # (sid) # найти имя наследуемого шаблона дизайна my $tpn = "default"; my $tpn2 = \'\'; @treewalk = tree_walk(shift); foreach my $i (reverse(@treewalk)) { if ($i->[2] ne \'\') { $tpn2 = $tpn; $tpn = $i->[2]; } } return ($tpn, $tpn2); } ###################################################################### sub get_tpl_list { # пполучить список доступных шаблонов дизайна my ($c, @ret) = 0; opendir(D, $tpl_dir); while (my $d = readdir(D)) { if ($d =~ m/^(.+)\\.asp$/) { push(@ret, $1); } } closedir(D); return sort @ret; } ###################################################################### sub tree_walk { # ($sid) # пройтись по дереву от указанного раздела до корня, записать в массив ($node, $secname, $sectpl) my ($node, $pnode, $secname, $sectpl, @tw) = shift; my $c = 0; while ($node != 0) { ($node, $pnode, $secname, $sectpl) = getonerec("select sid,secparent,secname,sectpl from section where sid=$node"); push(@tw, ([$node, $secname, $sectpl])); $node = $pnode; $c++; if ($c > 20) { # если очень большое количество итераций - значит в базе ошибка. my $t = \'\'; foreach (@tw) { $t .= \' \'.$_->[0]; } print error("В базе данных ошибка! Возможно зацикленная рекурсия. Срочно обратитесь к администратору.<br>tree_walk: [$t]"); last; } } return @tw; } ###################################################################### sub getonerec { # (query) # прочитать одну запись из базы my ($query, $st, @row) = shift; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]<br>\\n"; $st->execute() || print $db->errstr, ", Q:[$query]<br>\\n"; @row = $st->fetchrow_array; $st->finish; return @row; } ###################################################################### sub get_sql_list { # прочитать список из базы # return @arr = (\'a1\',\'b1\',\'c1\'); my $q = shift; my ($s,@r,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { push(@ret, $r[0]); } $s->finish; return @ret; } ###################################################################### sub get_sql_arr { # прочитать список списков (таблицу) из базы # return @arr = ( [\'a1\',\'a2\'], [\'b1\',\'b2\'], [\'c1\',\'c2\'] ); my $q = shift; my ($s,$rf,@r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { @rt = (); for my $i (0 .. scalar(@r)-1) { $rt[0][$i] = $r[$i]; } push(@ret, @rt); } $s->finish; return @ret; } ###################################################################### sub get_sql_arhash { # (query) # прочитать список хэшей (таблицу с именованными столбцами) из базы # return array of hashes my $q = shift; my ($s,$rf,$r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { push(@ret, $r); } $s->finish; return @ret; } ###################################################################### sub input_text { # ($name, $style, $value) # создать текстовое поле ввода my ($name, $style, $value) = @_; $style .= qq{ id="id$name"} if ($name); my $ret = qq{<input type="text" name="$name" value="$value" $style>}; return $ret; } ###################################################################### sub input_checkbox_1Y { # ($name, $style, $value, $label) # создать поле ввода чекбокс (одиночный) my ($name, $style, $value, $label) = @_; my $ret = ""; my $checked = (($value eq "Y") || ($value eq "on")) ? "checked" : ""; $zx_counter++; $ret = qq{<input type="checkbox" name="$name" id="id$zx_counter$name" $checked $style>&nbsp;<label for="id$zx_counter$name">$label</label>}; return $ret; } ###################################################################### sub input_radio { # ($name, $style, $js, $br, $checked, %values) # создать поле ввода радиоботтон (группу) my ($name, $style, $js, $br, $checked, %values) = @_; my $ret; my $j = ""; foreach my $i (sort keys %values) { if ($js ne \'\') { $j = qq{onclick="$js(\'$i\');"}; } my $checkstr = ($checked eq $i) ? "checked" : ""; $ret .= qq{<input type="radio" name="$name" id="$i" value="$i" $checkstr $style $j>\\n<label for="$i">$values{$i}</label>$br\\n}; } return $ret; } ###################################################################### sub input_textarea { # ($name, $style, $value) # создать поле тексареа my ($name, $style, $value) = @_; my $ret = qq{<textarea name="$name" $style>$value</textarea>}; return $ret; } ###################################################################### sub input_texteditor { # ($name, $imgdir, $value) # создать текстовый редактор на базе FCKeditor my ($name, $imgdir, $value) = @_; my $te = $Response->TrapInclude("page_fckeditor.asp", $name, $imgdir, $value); return $$te; } ###################################################################### sub input_list_arr { # ($name, $style, $currvalue, @arr) # создать поле список из 2d массива, с отключением отображения id # @arr = ( [1,\'a1\'], [2,\'a2\'], [3,\'a3\'] ); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); my $nonum = 0; my $size = qq{size="1"}; $size = $1 if ($style =~ s/(size=["\']*\\d+["\']*)//i); $nonum = 1 if ($style =~ s/nonum//i); $style .= qq{ id="id$name"} if ($name); $ret = qq{<select name="$name" $size $style>\\n}; for my $i (0 .. scalar(@arr)-1) { $sel = \'\'; if ($currvalue =~ m/^\\d+$/) { $sel = "selected" if ($arr[$i][0] == $currvalue); } else { $sel = "selected" if ($arr[$i][0] eq $currvalue); } if ($nonum) { $ret .= qq{<option $sel value="$arr[$i][0]">$arr[$i][1]</option>\\n}; } else { $ret .= qq{<option $sel value="$arr[$i][0]">[$arr[$i][0]] $arr[$i][1]</option>\\n}; } } $ret .= "</select>"; return $ret; } ###################################################################### sub input_list_arr_X1 { # ($name, $style, $currvalue, @arr) # создать поле список из 1d массива # @arr = (\'a1\',\'a2\',\'a3\'); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); $style .= qq{ id="id$name"} if ($name); $ret = "<select name=\\"$name\\" size=\\"1\\" $style>\\n"; foreach my $i (@arr) { if ($i eq $currvalue) { $sel = "selected"; } else { $sel = ""; } $ret .= qq{<option $sel value="$i">$i</option>\\n}; } $ret .= "</select>"; return $ret; } ###################################################################### sub check_acc { # ($sid, $acc_letters) # проверка прав доступа к разделу my ($sid, $acs) = @_; return 1 if ($godaccess); if ($sid =~ m/^\\d+$/) { #my @rghts = get_sql_list("select rights from usersacc where userid=$userinfo{id} and sid=$sid"); my $query = "select usersacc.rights from users inner join usersacc on (users.id = usersacc.userid) where users.enable = \'Y\' and users.id = $userinfo{id} and usersacc.sid = $sid"; my @rghts = get_sql_list($query); my $rights = join(\'\', @rghts); foreach my $ac (split(\'\', $acs)) { return 1 if ($rights =~ m/$ac/); } return 0; } return 0; } ###################################################################### sub tablist { # $sid, $pid, \'tabsheet\', \'focus\', startN, (array of names) # создание панели с закладками (используется в page.asp и section.asp) my ($sid, $pid, $tabsheet_name, $focus_name, $start_page, @pages) = @_; my $pagenum = scalar(@pages)-1; my ($out,$focus1,$focus2); =pod =head1 Параметры вызова: tablist($sid, $pid, \'tabsheet\', \'focus\', startN, (array of names)); =item $sid, $pid Номера раздела и страницы Если номер раздела < 0 - закладка со ссылкой на дерево объектов НЕ отображается. =item \'tabsheet\' HTML Идентификатор панели с табами =item startN Номер закладки, которую нужно открыть при старте страницы Для этого в запросе должен присутствовать параметр "ctsh=N" где N - номер закладки =item \'focus\' Идентификатор HTML объекта для установки фокуса при открытии каждой из закладок =item (array of names) Список строк, являющихся текстом на закладках =head1 Пример реализации панели с табами: <style> #tabsheet0 {display:none} /* в некоторых версяиях браузеров из за ошибки надо комментировать эту строку */ #tabsheet1 {display:none} #tabsheet2 {display:none} .tabsheet { ... } </style> <#% my @tabs = ( \'<img src="/pic/page1.png"> Page One\', \'<img src="/pic/page2.png"> Page Two\', \'<img src="/pic/page3.png"> Page Three\' ); my $ctsh; $ctsh = $FORM->{ctsh}; $ctsh = $QUERY->{ctsh} if ($ctsh eq \'\'); print tablist(-1, \'\', \'tabsheet\', \'fcs\', ($ctsh =~ m/[012]/)?$ctsh:0, @tabs); %#> <div class="tabarea"> <table border="0" width="100%" cellpadding="8" cellspacing="0"><tr><td> <div id="tabsheet0" class="tabsheet">Page 1<br><input type="text" id="fcs0"></div> <div id="tabsheet1" class="tabsheet">Page 2<br><input type="text" id="fcs1"></div> <div id="tabsheet2" class="tabsheet">Page 3<br><input type="text" id="fcs2"></div> </td></tr></table> </div> =cut my $css = qq[ <style> #tablist { padding: 3px 0 3px 6px; margin-left: 0; font: 13px Tahoma; /* line-height: 16px; */ white-space: nowrap; } #tablist li { list-style: none; margin: 0; display: inline; white-space: nowrap; } #tablist li a { color: #555; padding: 3px 6px; margin-left: 3px; border: 1px solid #888; border-bottom: none; background: #ddd; text-decoration: none; font-weight: normal; border-top-left-radius: 6px; border-top-right-radius: 6px; } </style> ]; my $javascript = qq[ <script language="JavaScript"> window.onload = function(){ showTab($start_page); } function showTab(tabnum) { for (i = 0; i <= $pagenum; i++) { document.getElementById(\'$tabsheet_name\'+i).style.display = \'none\'; tln = document.getElementById(\'xtl\'+i); tln.style.color = \'#555\'; tln.style.background = \'#ddd\'; tln.style.borderBottom = \'1px solid #888\'; } var tsheet = document.getElementById(\'$tabsheet_name\'+tabnum); var fcname = document.getElementById(\'$focus_name\'+tabnum); var tln = document.getElementById(\'xtl\'+tabnum); if (tsheet) { tsheet.style.display = \'block\'; } if (fcname) { fcname.focus(); } if (tln) { tln.style.color = \'#000\'; tln.style.background = \'white\'; tln.style.borderBottom = \'1px solid white\'; tln.style.backgroundImage = \'url(/admin/pic/tab_bg.gif)\'; } } </script]; # See ...Perl\\site\\lib\\Apache\\ASP\\GlobalASA.pm, lines 91,92... $out .= $css.$javascript.">\\n"; # stupid bug... $out .= qq{\\n<ul id="tablist" style="margin-bottom:0px;">\\n}; if ($sid > 0) { # отображение закладки со ссылкой на дерево объектов $out .= qq{ <li><a href="treejx.asp?sid=$sid&pid=$pid" style="padding-left:0;margin-left:0;background-color:#20a020;color:#c0ffc0;text-decoration:none" target="treeframe">&nbsp;<acronym title="Отобразить курсор на дереве объектов"><img src="/admin/pic/tree/node-tree.png" class="trico">&nbsp;$sid/$pid&nbsp;</acronym></a></li>\\n}; } for(my $i=0; $i<=$pagenum; $i++) { $pages[0] = qq{<span style="color:blue">$pages[0]</span>} if (($section{sectype} eq \'asp\') || ($sid == 0)); $out .= qq{ <li><a href="#$i" id="xtl$i" onclick="showTab($i)">$pages[$i]</a></li>\\n}; } $out .= qq{</ul>\\n}; return $out; } ####################################################################### sub get_indexgroup_str { # (index_name) # получить строку списка разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return $idx; } ####################################################################### sub get_indexgroup_lst { # (index_name) # получить список разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return split(/,\\s*/, $idx); } ####################################################################### sub exist_in_indexgroup { # ($index_name, $value) # проверить наличие $value в списке разделов по имени my ($index_name, $value) = @_; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return exist_in_list($value, split(/,\\s*/, $idx)); } ###################################################################### sub recalctree { # ($sid) # получить список всех подчиненных разделов от указанного my $sl = shift; $sl =~ s/\\D+/,/g; my @srvindex = (); my ($q, $s, $r); $q = "select sid from section order by sid"; $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { my @tw = (); @treewalk = &tree_walk($r->{sid}); foreach my $item (reverse @treewalk) { push(@tw, $item->[0]); } my %union = (); my %isect = (); # объединение и пересечение множеств @tw и "$sl", результат в %union и %isect foreach my $e (@tw, split(\',\', $sl)) { $union{$e}++ && $isect{$e}++ } push(@srvindex, $r->{sid}) if (scalar(keys %isect)); } $s->finish; return @srvindex; } ####################################################################### sub autorecalctree { # Обновление индексных групп при изменении иерархии разделов my $visual = shift; my ($q1, $s1, $r1); my ($q2, $s2, $r2); print qq{<div id="autoupdate" style="padding-top:10px;">Обновление индексных групп : } if ($visual); $q1 = "select id,slist from srvindex order by id desc"; $s1 = $db->prepare($q1) || print $db->errstr, ", query:[$q1]<br>\\n"; $s1->execute() || print $db->errstr, ", query:[$q1]<br>\\n"; while ( $r1 = $s1->fetchrow_hashref ) { print qq{<span style="background-color:blue;color:white">&nbsp;$r1->{id}&nbsp;</span>&nbsp;} if ($visual); $Response->Flush() if ($visual); # anti timeout solution my $flist = join(\',\', recalctree($r1->{slist})); $q2 = "update srvindex set flist=? where id=$r1->{id}"; $s2 = $db->prepare($q2) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->execute($flist) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->finish; } $s1->finish; print qq{\\n</div>\\n<style>#autoupdate {display:none} </style>\\n} if ($visual); } ####################################################################### sub check_for_secdel { # (sid) # проверка возможности удаления раздела my ($sid) = @_; my @cd_msg = (); my ($cs, $cp, $cf) = (0, 0, 0); my $filedir = "$uploaddir/$sid"; # считаем количество подразделов ($cs) = getonerec("select count(sid) from section where secparent = $sid"); push(@cd_msg, "Разделов: <span style=\'color:red\'>$cs</span>") if ($cs); # считаем количество документов в разделе ($cp) = getonerec("select count(pid) from documents where sid = $sid"); push(@cd_msg, "Страниц: <span style=\'color:red\'>$cp</span>") if ($cp); # считаем количество файлов в разделе if (opendir(D, $filedir)) { my @rm_dir = readdir(D); closedir(D); $cf = scalar(@rm_dir); # уменьшаем $cf из за служебных папок: \'.\' и \'..\' foreach my $d (@rm_dir) { $cf-- if ($d =~ m/^\\.+$/); } } push(@cd_msg, "Файлов: <span style=\'color:red\'>$cf</span>") if ($cf); return @cd_msg; } ###################################################################### sub get_section { # (sid) # прочитать информацию о разделе # return hash my ($sid) = @_; my (%ret, $query, $st, $row) = (); if ($sid > 0) { $query = "select * from section where sid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; } return %ret; } ###################################################################### sub get_document { # (sid, pid) # прочитать документ # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); $query = "select * from documents where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; $st->finish; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } return %ret; } ###################################################################### sub get_document_ex { # (sid, pid) # прочитать документ с расширенными полями # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); %ret = get_document($sid, $pid); $query = "select field,value from documents_ex where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { $ret{$row->{field}} = $row->{value}; } $st->finish; return %ret; } ###################################################################### sub get_sec_documents { # (sid, \'body\') # прочитать все документы раздела (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body) = @_; my (@ret, $query, $st, $row, $b) = (); $b = \'pagebody,\' if ($body); my $fields = "sid,pid,userid,url,pagename,".$b."pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus"; $query = "select $fields from documents where sid=? order by pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; return @ret; } ###################################################################### sub get_sec_documents_ex { # (sid, body, x_where) # прочитать все документы раздела с расширенными полями (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body, $x_where) = @_; my (@ret, @ret_ex, $query, $st, $row, $b) = (); $b = \'documents.pagebody,\' if ($body); my $fields = " documents.sid, documents.pid, documents.userid, documents.url, documents.pagename, $b documents.pagedate, documents.pagemodify, documents.pageorder, documents.sh_hdr, documents.sh_dir, documents.sh_nav, documents.sh_tab, documents.docstatus, documents_ex.field, documents_ex.value"; $query = "select $fields from documents left outer join documents_ex on (documents_ex.sid = documents.sid) and (documents_ex.pid = documents.pid) where documents.sid = $sid"; $query = "$query and ($x_where)" if ($x_where); # open(F, ">>$site_path/asa/q.log"); # print F "get_sec_documents_ex: $query\\n\\n"; # close(F); $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute() || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; # получили массив @ret с дублями строк для полей из documents my %h = (); foreach my $i (@ret) { # чтобы избавится от дублей пихаем строки в хэш, где ключ = \'sid.pid\' if (!defined($h{"$i->{sid}.$i->{pid}"})) { $h{"$i->{sid}.$i->{pid}"} = { \'sid\' => $i->{\'sid\'}, \'pid\' => $i->{\'pid\'}, \'userid\' => $i->{\'userid\'}, \'url\' => $i->{\'url\'}, \'pagename\' => $i->{\'pagename\'}, \'pagedate\' => $i->{\'pagedate\'}, \'pagemodify\' => $i->{\'pagemodify\'}, \'pageorder\' => $i->{\'pageorder\'}, \'sh_hdr\' => $i->{\'sh_hdr\'}, \'sh_dir\' => $i->{\'sh_dir\'}, \'sh_nav\' => $i->{\'sh_nav\'}, \'sh_tab\' => $i->{\'sh_tab\'}, \'docstatus\' => $i->{\'docstatus\'}, $i->{\'field\'} => $i->{\'value\'}, }; } else { # в случае сущесвования такой же строки в хэше - добавляем очередное поле из documents_ex $h{"$i->{sid}.$i->{pid}"}->{$i->{\'field\'}} = $i->{\'value\'}; } } @ret = (); # перекидываем всё из хэша в массив foreach my $i (keys %h) { push(@ret, $h{$i}); } return @ret; } ###################################################################### sub create_document { # (sid, userid, hash_fields) # создать документ в указанном разделе my ($sid, $userid, %fields) = @_; my ($pid, $query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # search new $pid for $sid my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $pid++; # set default values for new document $fields{pageorder} = $pid * 10; # insert new fields of document $query = "insert into documents (sid,pid,userid,url,pagename,pagebody,pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'create_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_document_ex { # (sid, userid, hash_fields) # создать документ с расширенными полями в указанном разделе my ($sid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { create_document($sid, $userid, %fields); my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $fields{pagebody} = \'\'; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'create_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document { # ($sid, $pid, $userid) # удалить документ my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document_ex { # ($sid, $pid, $userid) # удалить документ с расширенными полями my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); my %fields_ex = get_document_ex($sid, $pid); $query = "delete from documents_ex where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = \'\'; foreach my $i (keys %fields_ex) { $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'delete_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_section { # (sid) # удалить раздел my ($sid) = @_; my ($st, $query); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { $query = "delete from section where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); # remove rights for deleted section $query = "delete from usersacc where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document { # (sid, pid, userid, hash_fields) # заменить документ my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # update fields of document $query = "update documents set userid=?,url=?,pagename=?,pagebody=?,pagedate=?,pagemodify=?,pageorder=?,sh_hdr=?,sh_dir=?,sh_nav=?,sh_tab=?,docstatus=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'replace_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document_ex { # (sid, pid, userid, hash_fields) # заменить документ с расширенными полями my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { replace_document($sid, $pid, $userid, %fields); $fields{pagebody} = \'\'; # delete \'_ex\' fields in documents_ex $query = "delete from documents_ex where sid = $sid and pid = $pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]== $fields_ex{$i}\\n"; } journaldata(\'replace_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_section { # (hash_fields) # создать раздел my (%fields) = @_; my ($st, $sid, $query); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($secorder) = getonerec("select max(secorder) from section where secparent=$FORM->{secparent}"); $secorder = $secorder + 10; $fields{sectype} = $fields{sectype} || \'table\'; $fields{sorttype} = $fields{sorttype} || \'az\'; # insert record of section $query = "insert into section (secparent,secname,secdescr,sectype,plug_view,plug_admn,plug_ico,startpage,sorttype,secorder,sh_nav,sh_dir,sh_hdr) values (?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secparent}, $fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, ($fields{sectype} eq \'table\') ? $fields{startpage} : 0, $fields{sorttype}, $secorder, ($fields{sh_nav} eq "on") ? "Y" : "N", ($fields{sh_dir} eq "on") ? "Y" : "N", ($fields{sh_hdr} eq "on") ? "Y" : "N", ) || print $db->errstr, ", query:[$query]<br>\\n"; $sid = $db->{\'mysql_insertid\'}; logdata($query); # delete all rights for new section $query = "delete from usersacc where sid=$sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # copy rights from parent to current section $query = "insert into usersacc (userid,sid,rights) select userid,$sid,rights from usersacc where sid=$FORM->{secparent}"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return $sid; } ###################################################################### sub update_section { # (sid, hash_fields) # изменить раздел my ($sid, %fields) = @_; my ($st, $query); $fields{secparent} = 0 if (!defined($fields{secparent})); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); return -5 if (($fields{sectype} eq \'table\') && ($fields{startpage} !~ m/^\\-*\\d+$/)); return -6 if ($fields{secorder} !~ m/^\\d+$/); $fields{sorttype} = $fields{sorttype} || \'az\'; $fields{sh_nav} = ($fields{sh_nav} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_dir} = ($fields{sh_dir} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_hdr} = ($fields{sh_hdr} =~ m/on|Y/) ? \'Y\' : \'N\'; if ($fields{sectype} eq \'table\') { $fields{plug_view} = \'\'; $fields{plug_admn} = \'\'; $fields{plug_ico} = \'\'; } elsif ($fields{sectype} eq \'asp\') { $fields{startpage} = 0; } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { if ($godaccess) { # only GODS may change fields: \'plug_view, plug_admn, plug_ico, sec_tpl\' $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, plug_view=?, plug_admn=?, plug_ico=?, sectpl=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, $fields{template}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } else { $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub move_document { # ($sid, $pid, $new_sid, $userid) # переместить документ в другой раздел my ($sid, $pid, $new_sid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($new_pid, $new_pageorder) = getonerec("select max(pid),max(pageorder) from documents where sid=$new_sid"); $new_pid++; $new_pageorder = $new_pageorder + 10; my %fields = get_document($sid, $pid); $query = "update documents set userid=?, sid=?, pid=?, pageorder=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($userid, $new_sid, $new_pid, $new_pageorder) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = "Change: <b>$sid/$pid</b> to <b>$new_sid/$new_pid</b>"; journaldata(\'move_document\', $new_sid, $new_pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub journaldata { # ($func, $sid, $pid, $userid, %fields) # записать в журнал документ/раздел/сообщение my ($func, $sid, $pid, $userid, %fields) = @_; my $query = "insert into journal (ipaddr,function,sid,pid,userid,url,pagename,pagebody,pagedate,docstatus) values (?,?,?,?,?,?,?,?,?,?)"; my $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($remoteaddr, $func, $sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; } ###################################################################### sub cutwords { # ($string, $numwords) # отрезать от новостного сообщения начало в $numwords слов my ($str, $nw) = @_; my $ret; $str =~ s!<p(.*?)>! <p$1>!i; $str =~ s!<br>! <br>!i; $str =~ s!<div(.*?)>! <div$1>!i; $str =~ s!<(/*strong)>!%%$1%%!gi; $str =~ s!<(/*)b>!%%$1strong%%!gi; $str =~ s!<img (.+?)>!%%img $1%%!i; $str =~ s/(<(?=!--)([^>]|\\n)*--(?=>)>)//ig; $str =~ s/|(<\\/?([^>]|\\n)*>)//g; $str =~ s/&nbsp;/ /g; $str =~ s/\\s+/ /g; $str =~ s!%%(/*strong)%%!<$1>!gi; $str =~ s!%%img (.+?)%%!<img $1>!i; my @a = split(/\\s/, $str); if ($#a > $nw) { $ret = join(\' \', splice(@a, 0, $nw)) . qq{<b> . . .</b>}; } else { $ret = $str; } if (($ret =~ m!<strong>!) && ($ret !~ m!</strong>!)) { $ret .= "</strong>"; } return $ret; } ###################################################################### sub round { # округлить значение my $i = shift; return $i - int($i) < 0.5 ? int($i) : int($i)+1; } ###################################################################### sub rss_expand_img_url { # разворачивает URL картинки для RSS my ($u1, $u2, $u3) = @_; return "<img $u1"."src=\\"http://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_expand_hrf_url { # разворачивает URL ссылки для RSS my ($u1, $u2, $u3) = @_; return "<a $u1"."href=\\"https://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_clear_html_to_xml { # причесывает страницу по правилам XML my $txt = shift; $txt =~ s/<img (.*?)src="(.+?)"(.*?)>/rss_expand_img_url($1,$2,$3)/ige; $txt =~ s/<a (.*?)href="(.+?)"(.*?)>/rss_expand_hrf_url($1,$2,$3)/ige; $txt =~ s/&nbsp;/ /g; $txt =~ s/\\s+/ /g; $txt =~ s/&/&amp;/g; $txt =~ s/</&lt;/gi; return $txt; } ###################################################################### sub get_root_category { # для текущего раздела (что в последнем элементе массива @treewalk) ищет предка, у которого родитель = 4 if (@treewalk) { if (@treewalk[scalar(@treewalk)-1]->[0] == 4) { return @treewalk[scalar(@treewalk)-2]->[1]; } else { return @treewalk[scalar(@treewalk)-1]->[1]; } } else { return ""; } } ###################################################################### sub send_mail_smtp { # ($host, $from, $to, $body) my ($_host, $_from, $_to, $_xbody) = @_; $_xbody = "To: $_to\\n$_xbody"; my $smtp = Net::SMTP->new($_host, Hello => \'mail.arhcity.ru\', Timeout => 30); $smtp->mail($_from); $smtp->to($_to); $smtp->data(); $smtp->datasend($_xbody); $smtp->dataend(); $smtp->quit; } ###################################################################### sub get_cookie { # возвращает значение куки по ключу (см. \\asp\\admin\\lib\\adminlib.js) my $name = shift; my $cook = $SERVER->{HTTP_COOKIE}; my @arr = split(/;\\s*/, $cook); my %ck = (); foreach my $c (@arr) { my ($k, $v) = split(/=/, $c); $ck{$k} = $v; } return $ck{$name}; } ###################################################################### sub random_str { # возвращает строку указанной длинны (или 5) из случайных символов my $len = shift || 5; my $c = \'0123456789abcdefghijklmnopqrstuvwxyz\'; my $l = length($c); my $s = \'\'; for (1 .. $len) { $s .= substr($c, int(rand()*$l), 1); } return $s; } ###################################################################### sub check_body_style { # ( body ) my $body = shift; my (@cb_arr, @ret_txt) = (); @cb_arr = (); @cb_arr = $body =~ m!<(img|a).* (src|href)="data:image/(gif|png|jpeg);base64,(\\S+)"!sg; push(@ret_txt, "&bull; Недопустимое применение ссылок формата \\"data:image\\" (".(scalar(@cb_arr)/4)." раз.)") if (@cb_arr > 0); @cb_arr = (); @cb_arr = $body =~ m/<w:LsdException/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'LsdException\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/<w:WordDocument>/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'WordDocument\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/text-indent:27\\.0pt|class="MsoNormal"|tab-stops:list -9\\.0pt|mso-layout-grid-align:/sg; push(@ret_txt, "&bull; В тексте присутствуют инлайн-стили от Microsoft Word (".scalar(@cb_arr)." раз.)") if (@cb_arr > 4); @cb_arr = (); @cb_arr = $body =~ m/style="font-family: \'Times New Roman\'/sg; push(@ret_txt, "&bull; Слишком частое использование шрифта \'Times New Roman\' (".scalar(@cb_arr)." раз.)") if (@cb_arr > 5); @cb_arr = (); @cb_arr = $body =~ m/<span style="color: .+?;">|<span style="background-color: rgb(255, 255, 255);">/sg; push(@ret_txt, "&bull; Частое/неуместное использование цветового выделения (".scalar(@cb_arr)." раз.)") if (@cb_arr > 8); if (@ret_txt) { return join("<br>\\n", @ret_txt); } else { return 0; } } ###################################################################### sub meta_og_tags { # возвращает "Open Graph" тэги для страницы my ($sid, $pid) = @_; my $pageheader = $section{secname}; $pageheader = "Городские новости" if ($sid == 0); # https://ruogp.me/ - Протокол Open Graph my $r = \'\'; $r .= qq{<meta property="og:site_name" content="Администрация города Архангельска" />\\n}; $r .= qq{<meta property="og:url" content="http://arhcity.ru/?page=$sid/$pid" />\\n}; $r .= qq{<meta property="og:title" content="$pageheader" />\\n}; $r .= qq{<meta property="og:description" content="$document{pagename}" />\\n}; $r .= qq{<meta property="og:image" content="http://arhcity.ru/pic/og-image-arhcity.jpg" />\\n}; if ($section{sectype} eq \'table\') { my $_r = \'\'; my $c = 0; my @og_image = $document{pagebody} =~ m!<img src="(.+?)" .+/>!g; foreach my $i (@og_image) { $i =~ s!http://.+?\\.ru!!g; $_r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; $c++; } if ($c > 5) { # если картинок на странице много ( >5 ) - показываем только первую my $i = @og_image[0]; $i =~ s!http://.+?\\.ru!!g; $r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; } else { $r = $_r; } } return $r; } ###################################################################### sub gen_int_EO { # (number) # возвращает случайное чётное/нечётное число в интервале 0..number в зависимости от чётности number my $n = shift; my $r = int(rand() * $n); if ($n % 2 == 0) { $r++ if ($r % 2 == 1); } else { $r++ if ($r % 2 == 0); } return $r; } ###################################################################### sub update_msie_css { # внедряем в default.css значения переменных из colors.css и создаём default-ie.css my $ret = 0; my %vars = (); my $default_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default.css"; my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; my $default_ie_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default-ie.css"; my ($t_default_css) = (stat($default_css_fn))[9]; my ($t_colors_css) = (stat($colors_css_fn))[9]; my ($t_default_ie_css) = (stat($default_ie_css_fn))[9]; if (($t_default_css > $t_default_ie_css) || ($t_colors_css > $t_default_ie_css)) { open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); open(FS, "< $default_css_fn") || die "Can\'t open $default_css_fn, $!\\n"; open(FO, "> $default_ie_css_fn") || die "Can\'t open $default_ie_css_fn, $!\\n"; while (my $l = <FS>) { next if ($l =~ m/colors.css/); $l =~ s/(var\\((--.+?)\\))/exists($vars{$2})?$vars{$2}:\'none\'/gsex; print FO $l; } close(FO); close(FS); } $ret = 1 if ((stat($default_ie_css_fn))[7] > 0); # if filesize $default_ie_css_fn > 0 - file OK. return $ret; } ###################################################################### ## XML subroutines ################################################### ###################################################################### # see http://www.arhcity.ru/1.asp # ###################################################################### sub ipcms::button { my ($args, $html) = @_; my ($ico, $spacer); if (( $args->{ico}) && ( $args->{txt})) { $spacer = \'&nbsp;\'; } if ((!$args->{ico}) && ( $args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="1" height="16">\'; } if (( $args->{ico}) && (!$args->{txt})) { $spacer = \'\'; } if ((!$args->{ico}) && (!$args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="16" height="16">\'; } if ($args->{ico}) { $ico = qq{<img src="$args->{ico}" width="16" height="16">}; } print qq{<a href="$args->{url}"><div class="shbutton">}.$ico.$spacer.$args->{txt}.qq{</div></a>}; } ###################################################################### sub ipcms::panel { my ($args, $html) = @_; my ($o_style, $style); $o_style = $args->{style} if ($args->{style}); $style = qq{ style="$o_style"} if ($o_style); print qq{<div class="border_area"$style>$html<br>}; print_dump($args); print qq{</div>\\n}; } ;; sub exit { $main::Response->End(); } ;; no lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; 1;' called at /usr/local/share/perl5/Apache/ASP/GlobalASA.pm line 122 Apache::ASP::GlobalASA::new('Apache::ASP=HASH(0x562e3465c280)') called at /usr/local/share/perl5/Apache/ASP.pm line 389 Apache::ASP::new('Apache::ASP', 'Apache2::RequestRec=SCALAR(0x562e342fd2a8)', '/var/www/HDD2/mc.arhcity.ru/asp/index.asp') called at /usr/local/share/perl5/Apache/ASP.pm line 184 Apache::ASP::handler('Apache2::RequestRec=SCALAR(0x562e342fd2a8)') called at /usr/lib64/perl5/Errno.pm line 0 eval {...} called at /usr/lib64/perl5/Errno.pm line 0 Compilation failed in require at /usr/lib64/perl5/IO/Socket.pm line 18. at /usr/lib64/perl5/IO/Socket.pm line 18. IO::Socket::BEGIN() called at /usr/lib64/perl5/IO/Socket.pm line 18 eval {...} called at /usr/lib64/perl5/IO/Socket.pm line 18 require IO/Socket.pm called at /usr/share/perl5/Net/SMTP.pm line 15 Net::SMTP::BEGIN() called at /usr/lib64/perl5/IO/Socket.pm line 18 eval {...} called at /usr/lib64/perl5/IO/Socket.pm line 18 require Net/SMTP.pm called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax::BEGIN() called at /usr/lib64/perl5/IO/Socket.pm line 18 eval {...} called at /usr/lib64/perl5/IO/Socket.pm line 18 eval ' #line 1 /var/www/HDD2/mc.arhcity.ru/asa/global.asa package Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax; ;; use strict ;; use vars qw($Application $Session $Response $Server $Request); ;; use lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; #!/usr/bin/perl use Time::HiRes qw(gettimeofday tv_interval); use Apache::DBI; # automatic persistent database connections use DBI; use HTTP::Date; use Digest::SHA1 qw(sha1_hex sha1_base64); use Socket; use URI::UTF8::Punycode; use APR::UUID; use Text::Iconv; use Net::SMTP; # when PerlSetVar UseStrict setting on, need to declare # global variables with "use vars" ################################################################## # declare global variables use vars (\'$db\', # database interface \'$FORM\', # form data, method POST \'$QUERY\', # form data, method GET \'$POST\', # unformat form data, method POST \'$SERVER\', # server variables \'$localnet\', # access from local network \'$have_inet\', # access to internet \'$remoteaddr\', # remote IP address \'$useragent\', # UserAgent () \'$site_admin\', # Enable extra functions for site admins \'$logged_in\', # admin access by session \'$lc_logged_in\', # private cabinet access by session \'$servername\', # name of server \'$addrubrics\', # additional menu "rubrics" \'$tpl_dir\', # html template directory \'$godaccess\', # GOD access \'$hires_time\', # time generation of page ############################# \'%userinfo\', # entrie user data (hash) \'%section\', # entrie section data (hash) \'%document\', # entrie document data (hash) ############################# \'@treewalk\', # walking from leaf to root = ([$node, $secname, $sectpl]) \'%mod_params\', # parameters for plugins \'$zx_counter\', # counter for all unique repitable operations \'$site_url\', # url to site \'$site_path\', # path to site location \'$blindview\', # blind vew mode \'%CSS_vars\', # CSS variables ); ################################################################## my $host = \'localhost\'; my $db_name = \'ipcms3\'; my $dsn = "DBI:mysql:database=$db_name:host=$host"; my $username = \'root\'; my $password = \'\'; ################################################################## my $log_file; my $uploaddir; my $admin_dir = "/admin/"; my $lcab = "/lc/"; # list of datastore fields for separate \'_ex\' and non \'_ex\' fields my @doc_fields = qw(sid pid userid url pagename pagebody pagedate pagemodify pageorder sh_hdr sh_dir sh_nav sh_tab docstatus rating1 rating2); # at the begining of the page execution sub Script_OnStart { $hires_time = [gettimeofday]; $Response->Include("site_setup.asp"); # get default values for current site $log_file = "$site_path/datafiles/ipcms3.log"; $uploaddir = "$site_path/asp/data"; $Response->{\'ContentType\'} = "text/html"; $Response->{\'Charset\'} = "Windows-1251"; # $Response->{\'Expires\'} = 0; # page expired after NN seconds from download. # $Response->{\'Last-Modified:\'} = time2str(time-1); $FORM = $Request->Form(); $QUERY = $Request->QueryString(); # $POST = $Request->BinaryRead($Request->ServerVariables(\'CONTENT_LENGTH\')); # for debug $SERVER = $Request->ServerVariables(); $remoteaddr = $SERVER->{\'REMOTE_ADDR\'}; $servername = $SERVER->{\'SERVER_NAME\'}; $tpl_dir = $SERVER->{\'DOCUMENT_ROOT\'}."/templates"; $blindview = get_cookie("blindview") || 0; %userinfo = (); %section = (); %document = (); $addrubrics = \'\'; $site_admin = 0; $logged_in = 0; $godaccess = 0; $localnet = 0; $have_inet = 0; @treewalk = (); $zx_counter = 0; # Global Redirect Block... if ($servername eq \'arhcity.ru\') { $Response->Redirect("http://$site_url"); } if ($servername eq \'arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } if ($servername eq \'www.arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } # if ($SERVER->{HTTPS} ne \'on\') { # $Response->Redirect("https://www.arhcity.ru/?$SERVER->{QUERY_STRING}"); # } my $ic = Text::Iconv->new("UTF-8", "WINDOWS-1251"); my @r = (); foreach my $i (split(/\\./, $servername)) { if ($i =~ m/^xn--/) { push(@r, puny_dec($i)); } else { push(@r, $i); } } $servername = join(\'.\', @r); $servername = $ic->convert($servername); if ($SERVER->{HTTP_USER_AGENT} =~ m/edge/i) { $useragent = \'edge\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/chrome/i) { $useragent = \'chrome\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/webkit/i) { $useragent = \'safari\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/opera/i) { $useragent = \'opera\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/msie/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/trident/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/mozilla/i) { $useragent = \'mozilla\' } else { $useragent = \'unknown\'; } if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { # read CSS color variables for replace in html code (MSIE/Edge not support CSS vars); my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $CSS_vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); } if (($remoteaddr =~ m/^192\\.168\\./) || ($remoteaddr eq \'212.14.176.38\') || ($remoteaddr eq \'212.14.176.39\') || ($remoteaddr eq \'212.14.176.46\') || ($remoteaddr eq \'212.14.176.40\') || ($remoteaddr eq \'212.14.176.41\') || ($remoteaddr eq \'212.14.176.44\') || ($remoteaddr eq \'195.239.119.234\') # Городской центр гражданской защиты ) { $localnet = 1; } if (($localnet) && ( # Enable extra functions for site admins ($remoteaddr eq \'192.168.1.84\') || # GaidukAV ($remoteaddr eq \'192.168.1.44\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.45\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.46\' ) || # KorzhevDP ($remoteaddr eq \'192.168.51.144\') || # VishnyakovNS ($remoteaddr eq \'192.168.1.102\') || # EkimovKS v.1 ($remoteaddr eq \'192.168.1.110\') || # EkimovKS v.2 ($remoteaddr eq \'192.168.51.42\')) # EkimovKS v.3 ) { $site_admin = 1; } # connect to database $db = DBI->connect($dsn, $username, $password); if (! $db) { print "<p>Database server not responding.<br>Try later.</p>\\n"; $Response->End(); } # ONLY FOR RUSSIAN for MySQL !!! $db->do("set names cp1251"); if ($localnet) { # enable/disable outside scripts on site for local users without inet. ($have_inet) = getonerec("select count(ip) from squid_list where ip = \'$remoteaddr\'"); } else { $have_inet = 1; } # ------------------------------------------------------------ # $have_inet = 0; # !!! disable external scripts on site !!! # ------------------------------------------------------------ if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # !!! admin mode !!! $logged_in = 0; my $uname = $Session->{Authentication}; my $topframe = 0; if ($uname) { # logged in $logged_in = 1; $Session->{top_frame} = 0; my $adm_lib = $admin_dir . "lib/"; if ($SERVER->{\'REQUEST_URI\'} =~ m/$adm_lib/) { # read user info %userinfo = get_user_info($uname); $godaccess = 1 if ($userinfo{god} eq \'Y\'); if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no header } else { $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; } if ($SERVER->{\'REQUEST_URI\'} =~ m/(section.asp)|(page.asp)|(journal.asp)|(admin.asp)/i) { $Response->Include("page_autologoff.asp"); } } } else { # not logged in $topframe = $Session->{top_frame}; if (!$topframe) { my $location = "top.location.href=\'/admin/?t=".time()."\'"; print qq{<script>$location</script>}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n</body>\\n</html>\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with <style></style> definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "<pre>",Dumper(@_),"</pre>\\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n<script>\\n$location\\n</script".">\\n"; } ###################################################################### sub navigator { # отобразить навигатор (путь с корня до страницы) my @a = (\'<a href="/">Начало</a>\'); # if $sid in internal section (#6) - don\'t show any information my $rootsec = @treewalk[$#treewalk]; if ( (!$localnet) && ($rootsec->[0] == 6) ) { # ... } else { foreach my $i (reverse @treewalk) { push(@a, qq{<a href="/?page=$i->[0]/0">$i->[1]</a>}) if ($i->[0] > 0); } } return join(\' <span style="color:red"><img src="/pic/navar.gif" align="baseline"></span> \', @a); } ###################################################################### sub get_config_value { my $varname = shift; my ($varvalue) = getonerec("select varvalue from options where varname = \'$varname\'"); return $varvalue; } ###################################################################### sub store_config_value { my ($varname, $varvalue) = @_; my $query = "update options set varvalue=? where varname=?"; my $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($varvalue, $varname) || print $db->errstr, ", query:[$query]<br>\\n"; $st->finish; } ###################################################################### sub get_user_info { # прочитать информацию о зарегистрированном пользователе (по логину) # return hash my $user = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where username = \'$user\'"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub get_user_id_info { # прочитать информацию о зарегистрированном пользователе (по id) # return hash my $user_id = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where id = $user_id"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub make_pw_hash { # (password) # Создание уникального хэша по паролю my $password = shift; my $letts = \'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\'; my $lettl = length($letts); my $salt = \'\'; $password = substr($password, 0, 32) if (length($password) > 32); # limit password length for my $i (1 .. 5) { $salt .= substr($letts, int(rand() * $lettl), 1); } return $salt.sha1_base64($salt.$password); } ###################################################################### sub check_pw_hash { # (password, pwd_hash) # проверка на соответствие хэша и пароля my $password = shift; my $pw_hash = shift; my $salt = substr($pw_hash, 0, 5); $password = substr($password, 0, 32) if (length($password) > 32); # limit password length return (substr($pw_hash, 5) eq sha1_base64($salt.$password)); } ###################################################################### sub check_auth { # (user, password) # проверка авторизации my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'N\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub check_auth_lc { # (user, password) # проверка авторизации lcab my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'Y\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub get_inherit_tpl { # (sid) # найти имя наследуемого шаблона дизайна my $tpn = "default"; my $tpn2 = \'\'; @treewalk = tree_walk(shift); foreach my $i (reverse(@treewalk)) { if ($i->[2] ne \'\') { $tpn2 = $tpn; $tpn = $i->[2]; } } return ($tpn, $tpn2); } ###################################################################### sub get_tpl_list { # пполучить список доступных шаблонов дизайна my ($c, @ret) = 0; opendir(D, $tpl_dir); while (my $d = readdir(D)) { if ($d =~ m/^(.+)\\.asp$/) { push(@ret, $1); } } closedir(D); return sort @ret; } ###################################################################### sub tree_walk { # ($sid) # пройтись по дереву от указанного раздела до корня, записать в массив ($node, $secname, $sectpl) my ($node, $pnode, $secname, $sectpl, @tw) = shift; my $c = 0; while ($node != 0) { ($node, $pnode, $secname, $sectpl) = getonerec("select sid,secparent,secname,sectpl from section where sid=$node"); push(@tw, ([$node, $secname, $sectpl])); $node = $pnode; $c++; if ($c > 20) { # если очень большое количество итераций - значит в базе ошибка. my $t = \'\'; foreach (@tw) { $t .= \' \'.$_->[0]; } print error("В базе данных ошибка! Возможно зацикленная рекурсия. Срочно обратитесь к администратору.<br>tree_walk: [$t]"); last; } } return @tw; } ###################################################################### sub getonerec { # (query) # прочитать одну запись из базы my ($query, $st, @row) = shift; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]<br>\\n"; $st->execute() || print $db->errstr, ", Q:[$query]<br>\\n"; @row = $st->fetchrow_array; $st->finish; return @row; } ###################################################################### sub get_sql_list { # прочитать список из базы # return @arr = (\'a1\',\'b1\',\'c1\'); my $q = shift; my ($s,@r,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { push(@ret, $r[0]); } $s->finish; return @ret; } ###################################################################### sub get_sql_arr { # прочитать список списков (таблицу) из базы # return @arr = ( [\'a1\',\'a2\'], [\'b1\',\'b2\'], [\'c1\',\'c2\'] ); my $q = shift; my ($s,$rf,@r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { @rt = (); for my $i (0 .. scalar(@r)-1) { $rt[0][$i] = $r[$i]; } push(@ret, @rt); } $s->finish; return @ret; } ###################################################################### sub get_sql_arhash { # (query) # прочитать список хэшей (таблицу с именованными столбцами) из базы # return array of hashes my $q = shift; my ($s,$rf,$r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { push(@ret, $r); } $s->finish; return @ret; } ###################################################################### sub input_text { # ($name, $style, $value) # создать текстовое поле ввода my ($name, $style, $value) = @_; $style .= qq{ id="id$name"} if ($name); my $ret = qq{<input type="text" name="$name" value="$value" $style>}; return $ret; } ###################################################################### sub input_checkbox_1Y { # ($name, $style, $value, $label) # создать поле ввода чекбокс (одиночный) my ($name, $style, $value, $label) = @_; my $ret = ""; my $checked = (($value eq "Y") || ($value eq "on")) ? "checked" : ""; $zx_counter++; $ret = qq{<input type="checkbox" name="$name" id="id$zx_counter$name" $checked $style>&nbsp;<label for="id$zx_counter$name">$label</label>}; return $ret; } ###################################################################### sub input_radio { # ($name, $style, $js, $br, $checked, %values) # создать поле ввода радиоботтон (группу) my ($name, $style, $js, $br, $checked, %values) = @_; my $ret; my $j = ""; foreach my $i (sort keys %values) { if ($js ne \'\') { $j = qq{onclick="$js(\'$i\');"}; } my $checkstr = ($checked eq $i) ? "checked" : ""; $ret .= qq{<input type="radio" name="$name" id="$i" value="$i" $checkstr $style $j>\\n<label for="$i">$values{$i}</label>$br\\n}; } return $ret; } ###################################################################### sub input_textarea { # ($name, $style, $value) # создать поле тексареа my ($name, $style, $value) = @_; my $ret = qq{<textarea name="$name" $style>$value</textarea>}; return $ret; } ###################################################################### sub input_texteditor { # ($name, $imgdir, $value) # создать текстовый редактор на базе FCKeditor my ($name, $imgdir, $value) = @_; my $te = $Response->TrapInclude("page_fckeditor.asp", $name, $imgdir, $value); return $$te; } ###################################################################### sub input_list_arr { # ($name, $style, $currvalue, @arr) # создать поле список из 2d массива, с отключением отображения id # @arr = ( [1,\'a1\'], [2,\'a2\'], [3,\'a3\'] ); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); my $nonum = 0; my $size = qq{size="1"}; $size = $1 if ($style =~ s/(size=["\']*\\d+["\']*)//i); $nonum = 1 if ($style =~ s/nonum//i); $style .= qq{ id="id$name"} if ($name); $ret = qq{<select name="$name" $size $style>\\n}; for my $i (0 .. scalar(@arr)-1) { $sel = \'\'; if ($currvalue =~ m/^\\d+$/) { $sel = "selected" if ($arr[$i][0] == $currvalue); } else { $sel = "selected" if ($arr[$i][0] eq $currvalue); } if ($nonum) { $ret .= qq{<option $sel value="$arr[$i][0]">$arr[$i][1]</option>\\n}; } else { $ret .= qq{<option $sel value="$arr[$i][0]">[$arr[$i][0]] $arr[$i][1]</option>\\n}; } } $ret .= "</select>"; return $ret; } ###################################################################### sub input_list_arr_X1 { # ($name, $style, $currvalue, @arr) # создать поле список из 1d массива # @arr = (\'a1\',\'a2\',\'a3\'); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); $style .= qq{ id="id$name"} if ($name); $ret = "<select name=\\"$name\\" size=\\"1\\" $style>\\n"; foreach my $i (@arr) { if ($i eq $currvalue) { $sel = "selected"; } else { $sel = ""; } $ret .= qq{<option $sel value="$i">$i</option>\\n}; } $ret .= "</select>"; return $ret; } ###################################################################### sub check_acc { # ($sid, $acc_letters) # проверка прав доступа к разделу my ($sid, $acs) = @_; return 1 if ($godaccess); if ($sid =~ m/^\\d+$/) { #my @rghts = get_sql_list("select rights from usersacc where userid=$userinfo{id} and sid=$sid"); my $query = "select usersacc.rights from users inner join usersacc on (users.id = usersacc.userid) where users.enable = \'Y\' and users.id = $userinfo{id} and usersacc.sid = $sid"; my @rghts = get_sql_list($query); my $rights = join(\'\', @rghts); foreach my $ac (split(\'\', $acs)) { return 1 if ($rights =~ m/$ac/); } return 0; } return 0; } ###################################################################### sub tablist { # $sid, $pid, \'tabsheet\', \'focus\', startN, (array of names) # создание панели с закладками (используется в page.asp и section.asp) my ($sid, $pid, $tabsheet_name, $focus_name, $start_page, @pages) = @_; my $pagenum = scalar(@pages)-1; my ($out,$focus1,$focus2); =pod =head1 Параметры вызова: tablist($sid, $pid, \'tabsheet\', \'focus\', startN, (array of names)); =item $sid, $pid Номера раздела и страницы Если номер раздела < 0 - закладка со ссылкой на дерево объектов НЕ отображается. =item \'tabsheet\' HTML Идентификатор панели с табами =item startN Номер закладки, которую нужно открыть при старте страницы Для этого в запросе должен присутствовать параметр "ctsh=N" где N - номер закладки =item \'focus\' Идентификатор HTML объекта для установки фокуса при открытии каждой из закладок =item (array of names) Список строк, являющихся текстом на закладках =head1 Пример реализации панели с табами: <style> #tabsheet0 {display:none} /* в некоторых версяиях браузеров из за ошибки надо комментировать эту строку */ #tabsheet1 {display:none} #tabsheet2 {display:none} .tabsheet { ... } </style> <#% my @tabs = ( \'<img src="/pic/page1.png"> Page One\', \'<img src="/pic/page2.png"> Page Two\', \'<img src="/pic/page3.png"> Page Three\' ); my $ctsh; $ctsh = $FORM->{ctsh}; $ctsh = $QUERY->{ctsh} if ($ctsh eq \'\'); print tablist(-1, \'\', \'tabsheet\', \'fcs\', ($ctsh =~ m/[012]/)?$ctsh:0, @tabs); %#> <div class="tabarea"> <table border="0" width="100%" cellpadding="8" cellspacing="0"><tr><td> <div id="tabsheet0" class="tabsheet">Page 1<br><input type="text" id="fcs0"></div> <div id="tabsheet1" class="tabsheet">Page 2<br><input type="text" id="fcs1"></div> <div id="tabsheet2" class="tabsheet">Page 3<br><input type="text" id="fcs2"></div> </td></tr></table> </div> =cut my $css = qq[ <style> #tablist { padding: 3px 0 3px 6px; margin-left: 0; font: 13px Tahoma; /* line-height: 16px; */ white-space: nowrap; } #tablist li { list-style: none; margin: 0; display: inline; white-space: nowrap; } #tablist li a { color: #555; padding: 3px 6px; margin-left: 3px; border: 1px solid #888; border-bottom: none; background: #ddd; text-decoration: none; font-weight: normal; border-top-left-radius: 6px; border-top-right-radius: 6px; } </style> ]; my $javascript = qq[ <script language="JavaScript"> window.onload = function(){ showTab($start_page); } function showTab(tabnum) { for (i = 0; i <= $pagenum; i++) { document.getElementById(\'$tabsheet_name\'+i).style.display = \'none\'; tln = document.getElementById(\'xtl\'+i); tln.style.color = \'#555\'; tln.style.background = \'#ddd\'; tln.style.borderBottom = \'1px solid #888\'; } var tsheet = document.getElementById(\'$tabsheet_name\'+tabnum); var fcname = document.getElementById(\'$focus_name\'+tabnum); var tln = document.getElementById(\'xtl\'+tabnum); if (tsheet) { tsheet.style.display = \'block\'; } if (fcname) { fcname.focus(); } if (tln) { tln.style.color = \'#000\'; tln.style.background = \'white\'; tln.style.borderBottom = \'1px solid white\'; tln.style.backgroundImage = \'url(/admin/pic/tab_bg.gif)\'; } } </script]; # See ...Perl\\site\\lib\\Apache\\ASP\\GlobalASA.pm, lines 91,92... $out .= $css.$javascript.">\\n"; # stupid bug... $out .= qq{\\n<ul id="tablist" style="margin-bottom:0px;">\\n}; if ($sid > 0) { # отображение закладки со ссылкой на дерево объектов $out .= qq{ <li><a href="treejx.asp?sid=$sid&pid=$pid" style="padding-left:0;margin-left:0;background-color:#20a020;color:#c0ffc0;text-decoration:none" target="treeframe">&nbsp;<acronym title="Отобразить курсор на дереве объектов"><img src="/admin/pic/tree/node-tree.png" class="trico">&nbsp;$sid/$pid&nbsp;</acronym></a></li>\\n}; } for(my $i=0; $i<=$pagenum; $i++) { $pages[0] = qq{<span style="color:blue">$pages[0]</span>} if (($section{sectype} eq \'asp\') || ($sid == 0)); $out .= qq{ <li><a href="#$i" id="xtl$i" onclick="showTab($i)">$pages[$i]</a></li>\\n}; } $out .= qq{</ul>\\n}; return $out; } ####################################################################### sub get_indexgroup_str { # (index_name) # получить строку списка разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return $idx; } ####################################################################### sub get_indexgroup_lst { # (index_name) # получить список разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return split(/,\\s*/, $idx); } ####################################################################### sub exist_in_indexgroup { # ($index_name, $value) # проверить наличие $value в списке разделов по имени my ($index_name, $value) = @_; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return exist_in_list($value, split(/,\\s*/, $idx)); } ###################################################################### sub recalctree { # ($sid) # получить список всех подчиненных разделов от указанного my $sl = shift; $sl =~ s/\\D+/,/g; my @srvindex = (); my ($q, $s, $r); $q = "select sid from section order by sid"; $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { my @tw = (); @treewalk = &tree_walk($r->{sid}); foreach my $item (reverse @treewalk) { push(@tw, $item->[0]); } my %union = (); my %isect = (); # объединение и пересечение множеств @tw и "$sl", результат в %union и %isect foreach my $e (@tw, split(\',\', $sl)) { $union{$e}++ && $isect{$e}++ } push(@srvindex, $r->{sid}) if (scalar(keys %isect)); } $s->finish; return @srvindex; } ####################################################################### sub autorecalctree { # Обновление индексных групп при изменении иерархии разделов my $visual = shift; my ($q1, $s1, $r1); my ($q2, $s2, $r2); print qq{<div id="autoupdate" style="padding-top:10px;">Обновление индексных групп : } if ($visual); $q1 = "select id,slist from srvindex order by id desc"; $s1 = $db->prepare($q1) || print $db->errstr, ", query:[$q1]<br>\\n"; $s1->execute() || print $db->errstr, ", query:[$q1]<br>\\n"; while ( $r1 = $s1->fetchrow_hashref ) { print qq{<span style="background-color:blue;color:white">&nbsp;$r1->{id}&nbsp;</span>&nbsp;} if ($visual); $Response->Flush() if ($visual); # anti timeout solution my $flist = join(\',\', recalctree($r1->{slist})); $q2 = "update srvindex set flist=? where id=$r1->{id}"; $s2 = $db->prepare($q2) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->execute($flist) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->finish; } $s1->finish; print qq{\\n</div>\\n<style>#autoupdate {display:none} </style>\\n} if ($visual); } ####################################################################### sub check_for_secdel { # (sid) # проверка возможности удаления раздела my ($sid) = @_; my @cd_msg = (); my ($cs, $cp, $cf) = (0, 0, 0); my $filedir = "$uploaddir/$sid"; # считаем количество подразделов ($cs) = getonerec("select count(sid) from section where secparent = $sid"); push(@cd_msg, "Разделов: <span style=\'color:red\'>$cs</span>") if ($cs); # считаем количество документов в разделе ($cp) = getonerec("select count(pid) from documents where sid = $sid"); push(@cd_msg, "Страниц: <span style=\'color:red\'>$cp</span>") if ($cp); # считаем количество файлов в разделе if (opendir(D, $filedir)) { my @rm_dir = readdir(D); closedir(D); $cf = scalar(@rm_dir); # уменьшаем $cf из за служебных папок: \'.\' и \'..\' foreach my $d (@rm_dir) { $cf-- if ($d =~ m/^\\.+$/); } } push(@cd_msg, "Файлов: <span style=\'color:red\'>$cf</span>") if ($cf); return @cd_msg; } ###################################################################### sub get_section { # (sid) # прочитать информацию о разделе # return hash my ($sid) = @_; my (%ret, $query, $st, $row) = (); if ($sid > 0) { $query = "select * from section where sid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; } return %ret; } ###################################################################### sub get_document { # (sid, pid) # прочитать документ # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); $query = "select * from documents where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; $st->finish; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } return %ret; } ###################################################################### sub get_document_ex { # (sid, pid) # прочитать документ с расширенными полями # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); %ret = get_document($sid, $pid); $query = "select field,value from documents_ex where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { $ret{$row->{field}} = $row->{value}; } $st->finish; return %ret; } ###################################################################### sub get_sec_documents { # (sid, \'body\') # прочитать все документы раздела (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body) = @_; my (@ret, $query, $st, $row, $b) = (); $b = \'pagebody,\' if ($body); my $fields = "sid,pid,userid,url,pagename,".$b."pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus"; $query = "select $fields from documents where sid=? order by pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; return @ret; } ###################################################################### sub get_sec_documents_ex { # (sid, body, x_where) # прочитать все документы раздела с расширенными полями (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body, $x_where) = @_; my (@ret, @ret_ex, $query, $st, $row, $b) = (); $b = \'documents.pagebody,\' if ($body); my $fields = " documents.sid, documents.pid, documents.userid, documents.url, documents.pagename, $b documents.pagedate, documents.pagemodify, documents.pageorder, documents.sh_hdr, documents.sh_dir, documents.sh_nav, documents.sh_tab, documents.docstatus, documents_ex.field, documents_ex.value"; $query = "select $fields from documents left outer join documents_ex on (documents_ex.sid = documents.sid) and (documents_ex.pid = documents.pid) where documents.sid = $sid"; $query = "$query and ($x_where)" if ($x_where); # open(F, ">>$site_path/asa/q.log"); # print F "get_sec_documents_ex: $query\\n\\n"; # close(F); $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute() || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; # получили массив @ret с дублями строк для полей из documents my %h = (); foreach my $i (@ret) { # чтобы избавится от дублей пихаем строки в хэш, где ключ = \'sid.pid\' if (!defined($h{"$i->{sid}.$i->{pid}"})) { $h{"$i->{sid}.$i->{pid}"} = { \'sid\' => $i->{\'sid\'}, \'pid\' => $i->{\'pid\'}, \'userid\' => $i->{\'userid\'}, \'url\' => $i->{\'url\'}, \'pagename\' => $i->{\'pagename\'}, \'pagedate\' => $i->{\'pagedate\'}, \'pagemodify\' => $i->{\'pagemodify\'}, \'pageorder\' => $i->{\'pageorder\'}, \'sh_hdr\' => $i->{\'sh_hdr\'}, \'sh_dir\' => $i->{\'sh_dir\'}, \'sh_nav\' => $i->{\'sh_nav\'}, \'sh_tab\' => $i->{\'sh_tab\'}, \'docstatus\' => $i->{\'docstatus\'}, $i->{\'field\'} => $i->{\'value\'}, }; } else { # в случае сущесвования такой же строки в хэше - добавляем очередное поле из documents_ex $h{"$i->{sid}.$i->{pid}"}->{$i->{\'field\'}} = $i->{\'value\'}; } } @ret = (); # перекидываем всё из хэша в массив foreach my $i (keys %h) { push(@ret, $h{$i}); } return @ret; } ###################################################################### sub create_document { # (sid, userid, hash_fields) # создать документ в указанном разделе my ($sid, $userid, %fields) = @_; my ($pid, $query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # search new $pid for $sid my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $pid++; # set default values for new document $fields{pageorder} = $pid * 10; # insert new fields of document $query = "insert into documents (sid,pid,userid,url,pagename,pagebody,pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'create_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_document_ex { # (sid, userid, hash_fields) # создать документ с расширенными полями в указанном разделе my ($sid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { create_document($sid, $userid, %fields); my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $fields{pagebody} = \'\'; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'create_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document { # ($sid, $pid, $userid) # удалить документ my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document_ex { # ($sid, $pid, $userid) # удалить документ с расширенными полями my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); my %fields_ex = get_document_ex($sid, $pid); $query = "delete from documents_ex where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = \'\'; foreach my $i (keys %fields_ex) { $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'delete_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_section { # (sid) # удалить раздел my ($sid) = @_; my ($st, $query); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { $query = "delete from section where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); # remove rights for deleted section $query = "delete from usersacc where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document { # (sid, pid, userid, hash_fields) # заменить документ my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # update fields of document $query = "update documents set userid=?,url=?,pagename=?,pagebody=?,pagedate=?,pagemodify=?,pageorder=?,sh_hdr=?,sh_dir=?,sh_nav=?,sh_tab=?,docstatus=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'replace_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document_ex { # (sid, pid, userid, hash_fields) # заменить документ с расширенными полями my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { replace_document($sid, $pid, $userid, %fields); $fields{pagebody} = \'\'; # delete \'_ex\' fields in documents_ex $query = "delete from documents_ex where sid = $sid and pid = $pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]== $fields_ex{$i}\\n"; } journaldata(\'replace_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_section { # (hash_fields) # создать раздел my (%fields) = @_; my ($st, $sid, $query); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($secorder) = getonerec("select max(secorder) from section where secparent=$FORM->{secparent}"); $secorder = $secorder + 10; $fields{sectype} = $fields{sectype} || \'table\'; $fields{sorttype} = $fields{sorttype} || \'az\'; # insert record of section $query = "insert into section (secparent,secname,secdescr,sectype,plug_view,plug_admn,plug_ico,startpage,sorttype,secorder,sh_nav,sh_dir,sh_hdr) values (?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secparent}, $fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, ($fields{sectype} eq \'table\') ? $fields{startpage} : 0, $fields{sorttype}, $secorder, ($fields{sh_nav} eq "on") ? "Y" : "N", ($fields{sh_dir} eq "on") ? "Y" : "N", ($fields{sh_hdr} eq "on") ? "Y" : "N", ) || print $db->errstr, ", query:[$query]<br>\\n"; $sid = $db->{\'mysql_insertid\'}; logdata($query); # delete all rights for new section $query = "delete from usersacc where sid=$sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # copy rights from parent to current section $query = "insert into usersacc (userid,sid,rights) select userid,$sid,rights from usersacc where sid=$FORM->{secparent}"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return $sid; } ###################################################################### sub update_section { # (sid, hash_fields) # изменить раздел my ($sid, %fields) = @_; my ($st, $query); $fields{secparent} = 0 if (!defined($fields{secparent})); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); return -5 if (($fields{sectype} eq \'table\') && ($fields{startpage} !~ m/^\\-*\\d+$/)); return -6 if ($fields{secorder} !~ m/^\\d+$/); $fields{sorttype} = $fields{sorttype} || \'az\'; $fields{sh_nav} = ($fields{sh_nav} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_dir} = ($fields{sh_dir} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_hdr} = ($fields{sh_hdr} =~ m/on|Y/) ? \'Y\' : \'N\'; if ($fields{sectype} eq \'table\') { $fields{plug_view} = \'\'; $fields{plug_admn} = \'\'; $fields{plug_ico} = \'\'; } elsif ($fields{sectype} eq \'asp\') { $fields{startpage} = 0; } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { if ($godaccess) { # only GODS may change fields: \'plug_view, plug_admn, plug_ico, sec_tpl\' $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, plug_view=?, plug_admn=?, plug_ico=?, sectpl=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, $fields{template}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } else { $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub move_document { # ($sid, $pid, $new_sid, $userid) # переместить документ в другой раздел my ($sid, $pid, $new_sid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($new_pid, $new_pageorder) = getonerec("select max(pid),max(pageorder) from documents where sid=$new_sid"); $new_pid++; $new_pageorder = $new_pageorder + 10; my %fields = get_document($sid, $pid); $query = "update documents set userid=?, sid=?, pid=?, pageorder=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($userid, $new_sid, $new_pid, $new_pageorder) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = "Change: <b>$sid/$pid</b> to <b>$new_sid/$new_pid</b>"; journaldata(\'move_document\', $new_sid, $new_pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub journaldata { # ($func, $sid, $pid, $userid, %fields) # записать в журнал документ/раздел/сообщение my ($func, $sid, $pid, $userid, %fields) = @_; my $query = "insert into journal (ipaddr,function,sid,pid,userid,url,pagename,pagebody,pagedate,docstatus) values (?,?,?,?,?,?,?,?,?,?)"; my $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($remoteaddr, $func, $sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; } ###################################################################### sub cutwords { # ($string, $numwords) # отрезать от новостного сообщения начало в $numwords слов my ($str, $nw) = @_; my $ret; $str =~ s!<p(.*?)>! <p$1>!i; $str =~ s!<br>! <br>!i; $str =~ s!<div(.*?)>! <div$1>!i; $str =~ s!<(/*strong)>!%%$1%%!gi; $str =~ s!<(/*)b>!%%$1strong%%!gi; $str =~ s!<img (.+?)>!%%img $1%%!i; $str =~ s/(<(?=!--)([^>]|\\n)*--(?=>)>)//ig; $str =~ s/|(<\\/?([^>]|\\n)*>)//g; $str =~ s/&nbsp;/ /g; $str =~ s/\\s+/ /g; $str =~ s!%%(/*strong)%%!<$1>!gi; $str =~ s!%%img (.+?)%%!<img $1>!i; my @a = split(/\\s/, $str); if ($#a > $nw) { $ret = join(\' \', splice(@a, 0, $nw)) . qq{<b> . . .</b>}; } else { $ret = $str; } if (($ret =~ m!<strong>!) && ($ret !~ m!</strong>!)) { $ret .= "</strong>"; } return $ret; } ###################################################################### sub round { # округлить значение my $i = shift; return $i - int($i) < 0.5 ? int($i) : int($i)+1; } ###################################################################### sub rss_expand_img_url { # разворачивает URL картинки для RSS my ($u1, $u2, $u3) = @_; return "<img $u1"."src=\\"http://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_expand_hrf_url { # разворачивает URL ссылки для RSS my ($u1, $u2, $u3) = @_; return "<a $u1"."href=\\"https://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_clear_html_to_xml { # причесывает страницу по правилам XML my $txt = shift; $txt =~ s/<img (.*?)src="(.+?)"(.*?)>/rss_expand_img_url($1,$2,$3)/ige; $txt =~ s/<a (.*?)href="(.+?)"(.*?)>/rss_expand_hrf_url($1,$2,$3)/ige; $txt =~ s/&nbsp;/ /g; $txt =~ s/\\s+/ /g; $txt =~ s/&/&amp;/g; $txt =~ s/</&lt;/gi; return $txt; } ###################################################################### sub get_root_category { # для текущего раздела (что в последнем элементе массива @treewalk) ищет предка, у которого родитель = 4 if (@treewalk) { if (@treewalk[scalar(@treewalk)-1]->[0] == 4) { return @treewalk[scalar(@treewalk)-2]->[1]; } else { return @treewalk[scalar(@treewalk)-1]->[1]; } } else { return ""; } } ###################################################################### sub send_mail_smtp { # ($host, $from, $to, $body) my ($_host, $_from, $_to, $_xbody) = @_; $_xbody = "To: $_to\\n$_xbody"; my $smtp = Net::SMTP->new($_host, Hello => \'mail.arhcity.ru\', Timeout => 30); $smtp->mail($_from); $smtp->to($_to); $smtp->data(); $smtp->datasend($_xbody); $smtp->dataend(); $smtp->quit; } ###################################################################### sub get_cookie { # возвращает значение куки по ключу (см. \\asp\\admin\\lib\\adminlib.js) my $name = shift; my $cook = $SERVER->{HTTP_COOKIE}; my @arr = split(/;\\s*/, $cook); my %ck = (); foreach my $c (@arr) { my ($k, $v) = split(/=/, $c); $ck{$k} = $v; } return $ck{$name}; } ###################################################################### sub random_str { # возвращает строку указанной длинны (или 5) из случайных символов my $len = shift || 5; my $c = \'0123456789abcdefghijklmnopqrstuvwxyz\'; my $l = length($c); my $s = \'\'; for (1 .. $len) { $s .= substr($c, int(rand()*$l), 1); } return $s; } ###################################################################### sub check_body_style { # ( body ) my $body = shift; my (@cb_arr, @ret_txt) = (); @cb_arr = (); @cb_arr = $body =~ m!<(img|a).* (src|href)="data:image/(gif|png|jpeg);base64,(\\S+)"!sg; push(@ret_txt, "&bull; Недопустимое применение ссылок формата \\"data:image\\" (".(scalar(@cb_arr)/4)." раз.)") if (@cb_arr > 0); @cb_arr = (); @cb_arr = $body =~ m/<w:LsdException/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'LsdException\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/<w:WordDocument>/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'WordDocument\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/text-indent:27\\.0pt|class="MsoNormal"|tab-stops:list -9\\.0pt|mso-layout-grid-align:/sg; push(@ret_txt, "&bull; В тексте присутствуют инлайн-стили от Microsoft Word (".scalar(@cb_arr)." раз.)") if (@cb_arr > 4); @cb_arr = (); @cb_arr = $body =~ m/style="font-family: \'Times New Roman\'/sg; push(@ret_txt, "&bull; Слишком частое использование шрифта \'Times New Roman\' (".scalar(@cb_arr)." раз.)") if (@cb_arr > 5); @cb_arr = (); @cb_arr = $body =~ m/<span style="color: .+?;">|<span style="background-color: rgb(255, 255, 255);">/sg; push(@ret_txt, "&bull; Частое/неуместное использование цветового выделения (".scalar(@cb_arr)." раз.)") if (@cb_arr > 8); if (@ret_txt) { return join("<br>\\n", @ret_txt); } else { return 0; } } ###################################################################### sub meta_og_tags { # возвращает "Open Graph" тэги для страницы my ($sid, $pid) = @_; my $pageheader = $section{secname}; $pageheader = "Городские новости" if ($sid == 0); # https://ruogp.me/ - Протокол Open Graph my $r = \'\'; $r .= qq{<meta property="og:site_name" content="Администрация города Архангельска" />\\n}; $r .= qq{<meta property="og:url" content="http://arhcity.ru/?page=$sid/$pid" />\\n}; $r .= qq{<meta property="og:title" content="$pageheader" />\\n}; $r .= qq{<meta property="og:description" content="$document{pagename}" />\\n}; $r .= qq{<meta property="og:image" content="http://arhcity.ru/pic/og-image-arhcity.jpg" />\\n}; if ($section{sectype} eq \'table\') { my $_r = \'\'; my $c = 0; my @og_image = $document{pagebody} =~ m!<img src="(.+?)" .+/>!g; foreach my $i (@og_image) { $i =~ s!http://.+?\\.ru!!g; $_r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; $c++; } if ($c > 5) { # если картинок на странице много ( >5 ) - показываем только первую my $i = @og_image[0]; $i =~ s!http://.+?\\.ru!!g; $r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; } else { $r = $_r; } } return $r; } ###################################################################### sub gen_int_EO { # (number) # возвращает случайное чётное/нечётное число в интервале 0..number в зависимости от чётности number my $n = shift; my $r = int(rand() * $n); if ($n % 2 == 0) { $r++ if ($r % 2 == 1); } else { $r++ if ($r % 2 == 0); } return $r; } ###################################################################### sub update_msie_css { # внедряем в default.css значения переменных из colors.css и создаём default-ie.css my $ret = 0; my %vars = (); my $default_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default.css"; my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; my $default_ie_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default-ie.css"; my ($t_default_css) = (stat($default_css_fn))[9]; my ($t_colors_css) = (stat($colors_css_fn))[9]; my ($t_default_ie_css) = (stat($default_ie_css_fn))[9]; if (($t_default_css > $t_default_ie_css) || ($t_colors_css > $t_default_ie_css)) { open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); open(FS, "< $default_css_fn") || die "Can\'t open $default_css_fn, $!\\n"; open(FO, "> $default_ie_css_fn") || die "Can\'t open $default_ie_css_fn, $!\\n"; while (my $l = <FS>) { next if ($l =~ m/colors.css/); $l =~ s/(var\\((--.+?)\\))/exists($vars{$2})?$vars{$2}:\'none\'/gsex; print FO $l; } close(FO); close(FS); } $ret = 1 if ((stat($default_ie_css_fn))[7] > 0); # if filesize $default_ie_css_fn > 0 - file OK. return $ret; } ###################################################################### ## XML subroutines ################################################### ###################################################################### # see http://www.arhcity.ru/1.asp # ###################################################################### sub ipcms::button { my ($args, $html) = @_; my ($ico, $spacer); if (( $args->{ico}) && ( $args->{txt})) { $spacer = \'&nbsp;\'; } if ((!$args->{ico}) && ( $args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="1" height="16">\'; } if (( $args->{ico}) && (!$args->{txt})) { $spacer = \'\'; } if ((!$args->{ico}) && (!$args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="16" height="16">\'; } if ($args->{ico}) { $ico = qq{<img src="$args->{ico}" width="16" height="16">}; } print qq{<a href="$args->{url}"><div class="shbutton">}.$ico.$spacer.$args->{txt}.qq{</div></a>}; } ###################################################################### sub ipcms::panel { my ($args, $html) = @_; my ($o_style, $style); $o_style = $args->{style} if ($args->{style}); $style = qq{ style="$o_style"} if ($o_style); print qq{<div class="border_area"$style>$html<br>}; print_dump($args); print qq{</div>\\n}; } ;; sub exit { $main::Response->End(); } ;; no lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; 1;' called at /usr/local/share/perl5/Apache/ASP/GlobalASA.pm line 122 Apache::ASP::GlobalASA::new('Apache::ASP=HASH(0x562e3465c280)') called at /usr/local/share/perl5/Apache/ASP.pm line 389 Apache::ASP::new('Apache::ASP', 'Apache2::RequestRec=SCALAR(0x562e342fd2a8)', '/var/www/HDD2/mc.arhcity.ru/asp/index.asp') called at /usr/local/share/perl5/Apache/ASP.pm line 184 Apache::ASP::handler('Apache2::RequestRec=SCALAR(0x562e342fd2a8)') called at /usr/lib64/perl5/IO/Socket.pm line 18 eval {...} called at /usr/lib64/perl5/IO/Socket.pm line 18 BEGIN failed--compilation aborted at /usr/lib64/perl5/IO/Socket.pm line 18. at /usr/lib64/perl5/IO/Socket.pm line 18. require IO/Socket.pm called at /usr/share/perl5/Net/SMTP.pm line 15 Net::SMTP::BEGIN() called at /usr/lib64/perl5/IO/Socket.pm line 18 eval {...} called at /usr/lib64/perl5/IO/Socket.pm line 18 require Net/SMTP.pm called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax::BEGIN() called at /usr/lib64/perl5/IO/Socket.pm line 18 eval {...} called at /usr/lib64/perl5/IO/Socket.pm line 18 eval ' #line 1 /var/www/HDD2/mc.arhcity.ru/asa/global.asa package Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax; ;; use strict ;; use vars qw($Application $Session $Response $Server $Request); ;; use lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; #!/usr/bin/perl use Time::HiRes qw(gettimeofday tv_interval); use Apache::DBI; # automatic persistent database connections use DBI; use HTTP::Date; use Digest::SHA1 qw(sha1_hex sha1_base64); use Socket; use URI::UTF8::Punycode; use APR::UUID; use Text::Iconv; use Net::SMTP; # when PerlSetVar UseStrict setting on, need to declare # global variables with "use vars" ################################################################## # declare global variables use vars (\'$db\', # database interface \'$FORM\', # form data, method POST \'$QUERY\', # form data, method GET \'$POST\', # unformat form data, method POST \'$SERVER\', # server variables \'$localnet\', # access from local network \'$have_inet\', # access to internet \'$remoteaddr\', # remote IP address \'$useragent\', # UserAgent () \'$site_admin\', # Enable extra functions for site admins \'$logged_in\', # admin access by session \'$lc_logged_in\', # private cabinet access by session \'$servername\', # name of server \'$addrubrics\', # additional menu "rubrics" \'$tpl_dir\', # html template directory \'$godaccess\', # GOD access \'$hires_time\', # time generation of page ############################# \'%userinfo\', # entrie user data (hash) \'%section\', # entrie section data (hash) \'%document\', # entrie document data (hash) ############################# \'@treewalk\', # walking from leaf to root = ([$node, $secname, $sectpl]) \'%mod_params\', # parameters for plugins \'$zx_counter\', # counter for all unique repitable operations \'$site_url\', # url to site \'$site_path\', # path to site location \'$blindview\', # blind vew mode \'%CSS_vars\', # CSS variables ); ################################################################## my $host = \'localhost\'; my $db_name = \'ipcms3\'; my $dsn = "DBI:mysql:database=$db_name:host=$host"; my $username = \'root\'; my $password = \'\'; ################################################################## my $log_file; my $uploaddir; my $admin_dir = "/admin/"; my $lcab = "/lc/"; # list of datastore fields for separate \'_ex\' and non \'_ex\' fields my @doc_fields = qw(sid pid userid url pagename pagebody pagedate pagemodify pageorder sh_hdr sh_dir sh_nav sh_tab docstatus rating1 rating2); # at the begining of the page execution sub Script_OnStart { $hires_time = [gettimeofday]; $Response->Include("site_setup.asp"); # get default values for current site $log_file = "$site_path/datafiles/ipcms3.log"; $uploaddir = "$site_path/asp/data"; $Response->{\'ContentType\'} = "text/html"; $Response->{\'Charset\'} = "Windows-1251"; # $Response->{\'Expires\'} = 0; # page expired after NN seconds from download. # $Response->{\'Last-Modified:\'} = time2str(time-1); $FORM = $Request->Form(); $QUERY = $Request->QueryString(); # $POST = $Request->BinaryRead($Request->ServerVariables(\'CONTENT_LENGTH\')); # for debug $SERVER = $Request->ServerVariables(); $remoteaddr = $SERVER->{\'REMOTE_ADDR\'}; $servername = $SERVER->{\'SERVER_NAME\'}; $tpl_dir = $SERVER->{\'DOCUMENT_ROOT\'}."/templates"; $blindview = get_cookie("blindview") || 0; %userinfo = (); %section = (); %document = (); $addrubrics = \'\'; $site_admin = 0; $logged_in = 0; $godaccess = 0; $localnet = 0; $have_inet = 0; @treewalk = (); $zx_counter = 0; # Global Redirect Block... if ($servername eq \'arhcity.ru\') { $Response->Redirect("http://$site_url"); } if ($servername eq \'arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } if ($servername eq \'www.arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } # if ($SERVER->{HTTPS} ne \'on\') { # $Response->Redirect("https://www.arhcity.ru/?$SERVER->{QUERY_STRING}"); # } my $ic = Text::Iconv->new("UTF-8", "WINDOWS-1251"); my @r = (); foreach my $i (split(/\\./, $servername)) { if ($i =~ m/^xn--/) { push(@r, puny_dec($i)); } else { push(@r, $i); } } $servername = join(\'.\', @r); $servername = $ic->convert($servername); if ($SERVER->{HTTP_USER_AGENT} =~ m/edge/i) { $useragent = \'edge\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/chrome/i) { $useragent = \'chrome\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/webkit/i) { $useragent = \'safari\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/opera/i) { $useragent = \'opera\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/msie/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/trident/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/mozilla/i) { $useragent = \'mozilla\' } else { $useragent = \'unknown\'; } if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { # read CSS color variables for replace in html code (MSIE/Edge not support CSS vars); my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $CSS_vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); } if (($remoteaddr =~ m/^192\\.168\\./) || ($remoteaddr eq \'212.14.176.38\') || ($remoteaddr eq \'212.14.176.39\') || ($remoteaddr eq \'212.14.176.46\') || ($remoteaddr eq \'212.14.176.40\') || ($remoteaddr eq \'212.14.176.41\') || ($remoteaddr eq \'212.14.176.44\') || ($remoteaddr eq \'195.239.119.234\') # Городской центр гражданской защиты ) { $localnet = 1; } if (($localnet) && ( # Enable extra functions for site admins ($remoteaddr eq \'192.168.1.84\') || # GaidukAV ($remoteaddr eq \'192.168.1.44\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.45\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.46\' ) || # KorzhevDP ($remoteaddr eq \'192.168.51.144\') || # VishnyakovNS ($remoteaddr eq \'192.168.1.102\') || # EkimovKS v.1 ($remoteaddr eq \'192.168.1.110\') || # EkimovKS v.2 ($remoteaddr eq \'192.168.51.42\')) # EkimovKS v.3 ) { $site_admin = 1; } # connect to database $db = DBI->connect($dsn, $username, $password); if (! $db) { print "<p>Database server not responding.<br>Try later.</p>\\n"; $Response->End(); } # ONLY FOR RUSSIAN for MySQL !!! $db->do("set names cp1251"); if ($localnet) { # enable/disable outside scripts on site for local users without inet. ($have_inet) = getonerec("select count(ip) from squid_list where ip = \'$remoteaddr\'"); } else { $have_inet = 1; } # ------------------------------------------------------------ # $have_inet = 0; # !!! disable external scripts on site !!! # ------------------------------------------------------------ if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # !!! admin mode !!! $logged_in = 0; my $uname = $Session->{Authentication}; my $topframe = 0; if ($uname) { # logged in $logged_in = 1; $Session->{top_frame} = 0; my $adm_lib = $admin_dir . "lib/"; if ($SERVER->{\'REQUEST_URI\'} =~ m/$adm_lib/) { # read user info %userinfo = get_user_info($uname); $godaccess = 1 if ($userinfo{god} eq \'Y\'); if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no header } else { $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; } if ($SERVER->{\'REQUEST_URI\'} =~ m/(section.asp)|(page.asp)|(journal.asp)|(admin.asp)/i) { $Response->Include("page_autologoff.asp"); } } } else { # not logged in $topframe = $Session->{top_frame}; if (!$topframe) { my $location = "top.location.href=\'/admin/?t=".time()."\'"; print qq{<script>$location</script>}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n</body>\\n</html>\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with <style></style> definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "<pre>",Dumper(@_),"</pre>\\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n<script>\\n$location\\n</script".">\\n"; } ###################################################################### sub navigator { # отобразить навигатор (путь с корня до страницы) my @a = (\'<a href="/">Начало</a>\'); # if $sid in internal section (#6) - don\'t show any information my $rootsec = @treewalk[$#treewalk]; if ( (!$localnet) && ($rootsec->[0] == 6) ) { # ... } else { foreach my $i (reverse @treewalk) { push(@a, qq{<a href="/?page=$i->[0]/0">$i->[1]</a>}) if ($i->[0] > 0); } } return join(\' <span style="color:red"><img src="/pic/navar.gif" align="baseline"></span> \', @a); } ###################################################################### sub get_config_value { my $varname = shift; my ($varvalue) = getonerec("select varvalue from options where varname = \'$varname\'"); return $varvalue; } ###################################################################### sub store_config_value { my ($varname, $varvalue) = @_; my $query = "update options set varvalue=? where varname=?"; my $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($varvalue, $varname) || print $db->errstr, ", query:[$query]<br>\\n"; $st->finish; } ###################################################################### sub get_user_info { # прочитать информацию о зарегистрированном пользователе (по логину) # return hash my $user = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where username = \'$user\'"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub get_user_id_info { # прочитать информацию о зарегистрированном пользователе (по id) # return hash my $user_id = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where id = $user_id"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub make_pw_hash { # (password) # Создание уникального хэша по паролю my $password = shift; my $letts = \'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\'; my $lettl = length($letts); my $salt = \'\'; $password = substr($password, 0, 32) if (length($password) > 32); # limit password length for my $i (1 .. 5) { $salt .= substr($letts, int(rand() * $lettl), 1); } return $salt.sha1_base64($salt.$password); } ###################################################################### sub check_pw_hash { # (password, pwd_hash) # проверка на соответствие хэша и пароля my $password = shift; my $pw_hash = shift; my $salt = substr($pw_hash, 0, 5); $password = substr($password, 0, 32) if (length($password) > 32); # limit password length return (substr($pw_hash, 5) eq sha1_base64($salt.$password)); } ###################################################################### sub check_auth { # (user, password) # проверка авторизации my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'N\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub check_auth_lc { # (user, password) # проверка авторизации lcab my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'Y\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub get_inherit_tpl { # (sid) # найти имя наследуемого шаблона дизайна my $tpn = "default"; my $tpn2 = \'\'; @treewalk = tree_walk(shift); foreach my $i (reverse(@treewalk)) { if ($i->[2] ne \'\') { $tpn2 = $tpn; $tpn = $i->[2]; } } return ($tpn, $tpn2); } ###################################################################### sub get_tpl_list { # пполучить список доступных шаблонов дизайна my ($c, @ret) = 0; opendir(D, $tpl_dir); while (my $d = readdir(D)) { if ($d =~ m/^(.+)\\.asp$/) { push(@ret, $1); } } closedir(D); return sort @ret; } ###################################################################### sub tree_walk { # ($sid) # пройтись по дереву от указанного раздела до корня, записать в массив ($node, $secname, $sectpl) my ($node, $pnode, $secname, $sectpl, @tw) = shift; my $c = 0; while ($node != 0) { ($node, $pnode, $secname, $sectpl) = getonerec("select sid,secparent,secname,sectpl from section where sid=$node"); push(@tw, ([$node, $secname, $sectpl])); $node = $pnode; $c++; if ($c > 20) { # если очень большое количество итераций - значит в базе ошибка. my $t = \'\'; foreach (@tw) { $t .= \' \'.$_->[0]; } print error("В базе данных ошибка! Возможно зацикленная рекурсия. Срочно обратитесь к администратору.<br>tree_walk: [$t]"); last; } } return @tw; } ###################################################################### sub getonerec { # (query) # прочитать одну запись из базы my ($query, $st, @row) = shift; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]<br>\\n"; $st->execute() || print $db->errstr, ", Q:[$query]<br>\\n"; @row = $st->fetchrow_array; $st->finish; return @row; } ###################################################################### sub get_sql_list { # прочитать список из базы # return @arr = (\'a1\',\'b1\',\'c1\'); my $q = shift; my ($s,@r,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { push(@ret, $r[0]); } $s->finish; return @ret; } ###################################################################### sub get_sql_arr { # прочитать список списков (таблицу) из базы # return @arr = ( [\'a1\',\'a2\'], [\'b1\',\'b2\'], [\'c1\',\'c2\'] ); my $q = shift; my ($s,$rf,@r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { @rt = (); for my $i (0 .. scalar(@r)-1) { $rt[0][$i] = $r[$i]; } push(@ret, @rt); } $s->finish; return @ret; } ###################################################################### sub get_sql_arhash { # (query) # прочитать список хэшей (таблицу с именованными столбцами) из базы # return array of hashes my $q = shift; my ($s,$rf,$r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { push(@ret, $r); } $s->finish; return @ret; } ###################################################################### sub input_text { # ($name, $style, $value) # создать текстовое поле ввода my ($name, $style, $value) = @_; $style .= qq{ id="id$name"} if ($name); my $ret = qq{<input type="text" name="$name" value="$value" $style>}; return $ret; } ###################################################################### sub input_checkbox_1Y { # ($name, $style, $value, $label) # создать поле ввода чекбокс (одиночный) my ($name, $style, $value, $label) = @_; my $ret = ""; my $checked = (($value eq "Y") || ($value eq "on")) ? "checked" : ""; $zx_counter++; $ret = qq{<input type="checkbox" name="$name" id="id$zx_counter$name" $checked $style>&nbsp;<label for="id$zx_counter$name">$label</label>}; return $ret; } ###################################################################### sub input_radio { # ($name, $style, $js, $br, $checked, %values) # создать поле ввода радиоботтон (группу) my ($name, $style, $js, $br, $checked, %values) = @_; my $ret; my $j = ""; foreach my $i (sort keys %values) { if ($js ne \'\') { $j = qq{onclick="$js(\'$i\');"}; } my $checkstr = ($checked eq $i) ? "checked" : ""; $ret .= qq{<input type="radio" name="$name" id="$i" value="$i" $checkstr $style $j>\\n<label for="$i">$values{$i}</label>$br\\n}; } return $ret; } ###################################################################### sub input_textarea { # ($name, $style, $value) # создать поле тексареа my ($name, $style, $value) = @_; my $ret = qq{<textarea name="$name" $style>$value</textarea>}; return $ret; } ###################################################################### sub input_texteditor { # ($name, $imgdir, $value) # создать текстовый редактор на базе FCKeditor my ($name, $imgdir, $value) = @_; my $te = $Response->TrapInclude("page_fckeditor.asp", $name, $imgdir, $value); return $$te; } ###################################################################### sub input_list_arr { # ($name, $style, $currvalue, @arr) # создать поле список из 2d массива, с отключением отображения id # @arr = ( [1,\'a1\'], [2,\'a2\'], [3,\'a3\'] ); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); my $nonum = 0; my $size = qq{size="1"}; $size = $1 if ($style =~ s/(size=["\']*\\d+["\']*)//i); $nonum = 1 if ($style =~ s/nonum//i); $style .= qq{ id="id$name"} if ($name); $ret = qq{<select name="$name" $size $style>\\n}; for my $i (0 .. scalar(@arr)-1) { $sel = \'\'; if ($currvalue =~ m/^\\d+$/) { $sel = "selected" if ($arr[$i][0] == $currvalue); } else { $sel = "selected" if ($arr[$i][0] eq $currvalue); } if ($nonum) { $ret .= qq{<option $sel value="$arr[$i][0]">$arr[$i][1]</option>\\n}; } else { $ret .= qq{<option $sel value="$arr[$i][0]">[$arr[$i][0]] $arr[$i][1]</option>\\n}; } } $ret .= "</select>"; return $ret; } ###################################################################### sub input_list_arr_X1 { # ($name, $style, $currvalue, @arr) # создать поле список из 1d массива # @arr = (\'a1\',\'a2\',\'a3\'); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); $style .= qq{ id="id$name"} if ($name); $ret = "<select name=\\"$name\\" size=\\"1\\" $style>\\n"; foreach my $i (@arr) { if ($i eq $currvalue) { $sel = "selected"; } else { $sel = ""; } $ret .= qq{<option $sel value="$i">$i</option>\\n}; } $ret .= "</select>"; return $ret; } ###################################################################### sub check_acc { # ($sid, $acc_letters) # проверка прав доступа к разделу my ($sid, $acs) = @_; return 1 if ($godaccess); if ($sid =~ m/^\\d+$/) { #my @rghts = get_sql_list("select rights from usersacc where userid=$userinfo{id} and sid=$sid"); my $query = "select usersacc.rights from users inner join usersacc on (users.id = usersacc.userid) where users.enable = \'Y\' and users.id = $userinfo{id} and usersacc.sid = $sid"; my @rghts = get_sql_list($query); my $rights = join(\'\', @rghts); foreach my $ac (split(\'\', $acs)) { return 1 if ($rights =~ m/$ac/); } return 0; } return 0; } ###################################################################### sub tablist { # $sid, $pid, \'tabsheet\', \'focus\', startN, (array of names) # создание панели с закладками (используется в page.asp и section.asp) my ($sid, $pid, $tabsheet_name, $focus_name, $start_page, @pages) = @_; my $pagenum = scalar(@pages)-1; my ($out,$focus1,$focus2); =pod =head1 Параметры вызова: tablist($sid, $pid, \'tabsheet\', \'focus\', startN, (array of names)); =item $sid, $pid Номера раздела и страницы Если номер раздела < 0 - закладка со ссылкой на дерево объектов НЕ отображается. =item \'tabsheet\' HTML Идентификатор панели с табами =item startN Номер закладки, которую нужно открыть при старте страницы Для этого в запросе должен присутствовать параметр "ctsh=N" где N - номер закладки =item \'focus\' Идентификатор HTML объекта для установки фокуса при открытии каждой из закладок =item (array of names) Список строк, являющихся текстом на закладках =head1 Пример реализации панели с табами: <style> #tabsheet0 {display:none} /* в некоторых версяиях браузеров из за ошибки надо комментировать эту строку */ #tabsheet1 {display:none} #tabsheet2 {display:none} .tabsheet { ... } </style> <#% my @tabs = ( \'<img src="/pic/page1.png"> Page One\', \'<img src="/pic/page2.png"> Page Two\', \'<img src="/pic/page3.png"> Page Three\' ); my $ctsh; $ctsh = $FORM->{ctsh}; $ctsh = $QUERY->{ctsh} if ($ctsh eq \'\'); print tablist(-1, \'\', \'tabsheet\', \'fcs\', ($ctsh =~ m/[012]/)?$ctsh:0, @tabs); %#> <div class="tabarea"> <table border="0" width="100%" cellpadding="8" cellspacing="0"><tr><td> <div id="tabsheet0" class="tabsheet">Page 1<br><input type="text" id="fcs0"></div> <div id="tabsheet1" class="tabsheet">Page 2<br><input type="text" id="fcs1"></div> <div id="tabsheet2" class="tabsheet">Page 3<br><input type="text" id="fcs2"></div> </td></tr></table> </div> =cut my $css = qq[ <style> #tablist { padding: 3px 0 3px 6px; margin-left: 0; font: 13px Tahoma; /* line-height: 16px; */ white-space: nowrap; } #tablist li { list-style: none; margin: 0; display: inline; white-space: nowrap; } #tablist li a { color: #555; padding: 3px 6px; margin-left: 3px; border: 1px solid #888; border-bottom: none; background: #ddd; text-decoration: none; font-weight: normal; border-top-left-radius: 6px; border-top-right-radius: 6px; } </style> ]; my $javascript = qq[ <script language="JavaScript"> window.onload = function(){ showTab($start_page); } function showTab(tabnum) { for (i = 0; i <= $pagenum; i++) { document.getElementById(\'$tabsheet_name\'+i).style.display = \'none\'; tln = document.getElementById(\'xtl\'+i); tln.style.color = \'#555\'; tln.style.background = \'#ddd\'; tln.style.borderBottom = \'1px solid #888\'; } var tsheet = document.getElementById(\'$tabsheet_name\'+tabnum); var fcname = document.getElementById(\'$focus_name\'+tabnum); var tln = document.getElementById(\'xtl\'+tabnum); if (tsheet) { tsheet.style.display = \'block\'; } if (fcname) { fcname.focus(); } if (tln) { tln.style.color = \'#000\'; tln.style.background = \'white\'; tln.style.borderBottom = \'1px solid white\'; tln.style.backgroundImage = \'url(/admin/pic/tab_bg.gif)\'; } } </script]; # See ...Perl\\site\\lib\\Apache\\ASP\\GlobalASA.pm, lines 91,92... $out .= $css.$javascript.">\\n"; # stupid bug... $out .= qq{\\n<ul id="tablist" style="margin-bottom:0px;">\\n}; if ($sid > 0) { # отображение закладки со ссылкой на дерево объектов $out .= qq{ <li><a href="treejx.asp?sid=$sid&pid=$pid" style="padding-left:0;margin-left:0;background-color:#20a020;color:#c0ffc0;text-decoration:none" target="treeframe">&nbsp;<acronym title="Отобразить курсор на дереве объектов"><img src="/admin/pic/tree/node-tree.png" class="trico">&nbsp;$sid/$pid&nbsp;</acronym></a></li>\\n}; } for(my $i=0; $i<=$pagenum; $i++) { $pages[0] = qq{<span style="color:blue">$pages[0]</span>} if (($section{sectype} eq \'asp\') || ($sid == 0)); $out .= qq{ <li><a href="#$i" id="xtl$i" onclick="showTab($i)">$pages[$i]</a></li>\\n}; } $out .= qq{</ul>\\n}; return $out; } ####################################################################### sub get_indexgroup_str { # (index_name) # получить строку списка разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return $idx; } ####################################################################### sub get_indexgroup_lst { # (index_name) # получить список разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return split(/,\\s*/, $idx); } ####################################################################### sub exist_in_indexgroup { # ($index_name, $value) # проверить наличие $value в списке разделов по имени my ($index_name, $value) = @_; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return exist_in_list($value, split(/,\\s*/, $idx)); } ###################################################################### sub recalctree { # ($sid) # получить список всех подчиненных разделов от указанного my $sl = shift; $sl =~ s/\\D+/,/g; my @srvindex = (); my ($q, $s, $r); $q = "select sid from section order by sid"; $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { my @tw = (); @treewalk = &tree_walk($r->{sid}); foreach my $item (reverse @treewalk) { push(@tw, $item->[0]); } my %union = (); my %isect = (); # объединение и пересечение множеств @tw и "$sl", результат в %union и %isect foreach my $e (@tw, split(\',\', $sl)) { $union{$e}++ && $isect{$e}++ } push(@srvindex, $r->{sid}) if (scalar(keys %isect)); } $s->finish; return @srvindex; } ####################################################################### sub autorecalctree { # Обновление индексных групп при изменении иерархии разделов my $visual = shift; my ($q1, $s1, $r1); my ($q2, $s2, $r2); print qq{<div id="autoupdate" style="padding-top:10px;">Обновление индексных групп : } if ($visual); $q1 = "select id,slist from srvindex order by id desc"; $s1 = $db->prepare($q1) || print $db->errstr, ", query:[$q1]<br>\\n"; $s1->execute() || print $db->errstr, ", query:[$q1]<br>\\n"; while ( $r1 = $s1->fetchrow_hashref ) { print qq{<span style="background-color:blue;color:white">&nbsp;$r1->{id}&nbsp;</span>&nbsp;} if ($visual); $Response->Flush() if ($visual); # anti timeout solution my $flist = join(\',\', recalctree($r1->{slist})); $q2 = "update srvindex set flist=? where id=$r1->{id}"; $s2 = $db->prepare($q2) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->execute($flist) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->finish; } $s1->finish; print qq{\\n</div>\\n<style>#autoupdate {display:none} </style>\\n} if ($visual); } ####################################################################### sub check_for_secdel { # (sid) # проверка возможности удаления раздела my ($sid) = @_; my @cd_msg = (); my ($cs, $cp, $cf) = (0, 0, 0); my $filedir = "$uploaddir/$sid"; # считаем количество подразделов ($cs) = getonerec("select count(sid) from section where secparent = $sid"); push(@cd_msg, "Разделов: <span style=\'color:red\'>$cs</span>") if ($cs); # считаем количество документов в разделе ($cp) = getonerec("select count(pid) from documents where sid = $sid"); push(@cd_msg, "Страниц: <span style=\'color:red\'>$cp</span>") if ($cp); # считаем количество файлов в разделе if (opendir(D, $filedir)) { my @rm_dir = readdir(D); closedir(D); $cf = scalar(@rm_dir); # уменьшаем $cf из за служебных папок: \'.\' и \'..\' foreach my $d (@rm_dir) { $cf-- if ($d =~ m/^\\.+$/); } } push(@cd_msg, "Файлов: <span style=\'color:red\'>$cf</span>") if ($cf); return @cd_msg; } ###################################################################### sub get_section { # (sid) # прочитать информацию о разделе # return hash my ($sid) = @_; my (%ret, $query, $st, $row) = (); if ($sid > 0) { $query = "select * from section where sid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; } return %ret; } ###################################################################### sub get_document { # (sid, pid) # прочитать документ # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); $query = "select * from documents where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; $st->finish; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } return %ret; } ###################################################################### sub get_document_ex { # (sid, pid) # прочитать документ с расширенными полями # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); %ret = get_document($sid, $pid); $query = "select field,value from documents_ex where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { $ret{$row->{field}} = $row->{value}; } $st->finish; return %ret; } ###################################################################### sub get_sec_documents { # (sid, \'body\') # прочитать все документы раздела (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body) = @_; my (@ret, $query, $st, $row, $b) = (); $b = \'pagebody,\' if ($body); my $fields = "sid,pid,userid,url,pagename,".$b."pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus"; $query = "select $fields from documents where sid=? order by pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; return @ret; } ###################################################################### sub get_sec_documents_ex { # (sid, body, x_where) # прочитать все документы раздела с расширенными полями (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body, $x_where) = @_; my (@ret, @ret_ex, $query, $st, $row, $b) = (); $b = \'documents.pagebody,\' if ($body); my $fields = " documents.sid, documents.pid, documents.userid, documents.url, documents.pagename, $b documents.pagedate, documents.pagemodify, documents.pageorder, documents.sh_hdr, documents.sh_dir, documents.sh_nav, documents.sh_tab, documents.docstatus, documents_ex.field, documents_ex.value"; $query = "select $fields from documents left outer join documents_ex on (documents_ex.sid = documents.sid) and (documents_ex.pid = documents.pid) where documents.sid = $sid"; $query = "$query and ($x_where)" if ($x_where); # open(F, ">>$site_path/asa/q.log"); # print F "get_sec_documents_ex: $query\\n\\n"; # close(F); $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute() || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; # получили массив @ret с дублями строк для полей из documents my %h = (); foreach my $i (@ret) { # чтобы избавится от дублей пихаем строки в хэш, где ключ = \'sid.pid\' if (!defined($h{"$i->{sid}.$i->{pid}"})) { $h{"$i->{sid}.$i->{pid}"} = { \'sid\' => $i->{\'sid\'}, \'pid\' => $i->{\'pid\'}, \'userid\' => $i->{\'userid\'}, \'url\' => $i->{\'url\'}, \'pagename\' => $i->{\'pagename\'}, \'pagedate\' => $i->{\'pagedate\'}, \'pagemodify\' => $i->{\'pagemodify\'}, \'pageorder\' => $i->{\'pageorder\'}, \'sh_hdr\' => $i->{\'sh_hdr\'}, \'sh_dir\' => $i->{\'sh_dir\'}, \'sh_nav\' => $i->{\'sh_nav\'}, \'sh_tab\' => $i->{\'sh_tab\'}, \'docstatus\' => $i->{\'docstatus\'}, $i->{\'field\'} => $i->{\'value\'}, }; } else { # в случае сущесвования такой же строки в хэше - добавляем очередное поле из documents_ex $h{"$i->{sid}.$i->{pid}"}->{$i->{\'field\'}} = $i->{\'value\'}; } } @ret = (); # перекидываем всё из хэша в массив foreach my $i (keys %h) { push(@ret, $h{$i}); } return @ret; } ###################################################################### sub create_document { # (sid, userid, hash_fields) # создать документ в указанном разделе my ($sid, $userid, %fields) = @_; my ($pid, $query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # search new $pid for $sid my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $pid++; # set default values for new document $fields{pageorder} = $pid * 10; # insert new fields of document $query = "insert into documents (sid,pid,userid,url,pagename,pagebody,pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'create_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_document_ex { # (sid, userid, hash_fields) # создать документ с расширенными полями в указанном разделе my ($sid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { create_document($sid, $userid, %fields); my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $fields{pagebody} = \'\'; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'create_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document { # ($sid, $pid, $userid) # удалить документ my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document_ex { # ($sid, $pid, $userid) # удалить документ с расширенными полями my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); my %fields_ex = get_document_ex($sid, $pid); $query = "delete from documents_ex where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = \'\'; foreach my $i (keys %fields_ex) { $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'delete_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_section { # (sid) # удалить раздел my ($sid) = @_; my ($st, $query); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { $query = "delete from section where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); # remove rights for deleted section $query = "delete from usersacc where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document { # (sid, pid, userid, hash_fields) # заменить документ my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # update fields of document $query = "update documents set userid=?,url=?,pagename=?,pagebody=?,pagedate=?,pagemodify=?,pageorder=?,sh_hdr=?,sh_dir=?,sh_nav=?,sh_tab=?,docstatus=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'replace_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document_ex { # (sid, pid, userid, hash_fields) # заменить документ с расширенными полями my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { replace_document($sid, $pid, $userid, %fields); $fields{pagebody} = \'\'; # delete \'_ex\' fields in documents_ex $query = "delete from documents_ex where sid = $sid and pid = $pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]== $fields_ex{$i}\\n"; } journaldata(\'replace_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_section { # (hash_fields) # создать раздел my (%fields) = @_; my ($st, $sid, $query); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($secorder) = getonerec("select max(secorder) from section where secparent=$FORM->{secparent}"); $secorder = $secorder + 10; $fields{sectype} = $fields{sectype} || \'table\'; $fields{sorttype} = $fields{sorttype} || \'az\'; # insert record of section $query = "insert into section (secparent,secname,secdescr,sectype,plug_view,plug_admn,plug_ico,startpage,sorttype,secorder,sh_nav,sh_dir,sh_hdr) values (?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secparent}, $fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, ($fields{sectype} eq \'table\') ? $fields{startpage} : 0, $fields{sorttype}, $secorder, ($fields{sh_nav} eq "on") ? "Y" : "N", ($fields{sh_dir} eq "on") ? "Y" : "N", ($fields{sh_hdr} eq "on") ? "Y" : "N", ) || print $db->errstr, ", query:[$query]<br>\\n"; $sid = $db->{\'mysql_insertid\'}; logdata($query); # delete all rights for new section $query = "delete from usersacc where sid=$sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # copy rights from parent to current section $query = "insert into usersacc (userid,sid,rights) select userid,$sid,rights from usersacc where sid=$FORM->{secparent}"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return $sid; } ###################################################################### sub update_section { # (sid, hash_fields) # изменить раздел my ($sid, %fields) = @_; my ($st, $query); $fields{secparent} = 0 if (!defined($fields{secparent})); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); return -5 if (($fields{sectype} eq \'table\') && ($fields{startpage} !~ m/^\\-*\\d+$/)); return -6 if ($fields{secorder} !~ m/^\\d+$/); $fields{sorttype} = $fields{sorttype} || \'az\'; $fields{sh_nav} = ($fields{sh_nav} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_dir} = ($fields{sh_dir} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_hdr} = ($fields{sh_hdr} =~ m/on|Y/) ? \'Y\' : \'N\'; if ($fields{sectype} eq \'table\') { $fields{plug_view} = \'\'; $fields{plug_admn} = \'\'; $fields{plug_ico} = \'\'; } elsif ($fields{sectype} eq \'asp\') { $fields{startpage} = 0; } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { if ($godaccess) { # only GODS may change fields: \'plug_view, plug_admn, plug_ico, sec_tpl\' $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, plug_view=?, plug_admn=?, plug_ico=?, sectpl=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, $fields{template}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } else { $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub move_document { # ($sid, $pid, $new_sid, $userid) # переместить документ в другой раздел my ($sid, $pid, $new_sid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($new_pid, $new_pageorder) = getonerec("select max(pid),max(pageorder) from documents where sid=$new_sid"); $new_pid++; $new_pageorder = $new_pageorder + 10; my %fields = get_document($sid, $pid); $query = "update documents set userid=?, sid=?, pid=?, pageorder=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($userid, $new_sid, $new_pid, $new_pageorder) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = "Change: <b>$sid/$pid</b> to <b>$new_sid/$new_pid</b>"; journaldata(\'move_document\', $new_sid, $new_pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub journaldata { # ($func, $sid, $pid, $userid, %fields) # записать в журнал документ/раздел/сообщение my ($func, $sid, $pid, $userid, %fields) = @_; my $query = "insert into journal (ipaddr,function,sid,pid,userid,url,pagename,pagebody,pagedate,docstatus) values (?,?,?,?,?,?,?,?,?,?)"; my $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($remoteaddr, $func, $sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; } ###################################################################### sub cutwords { # ($string, $numwords) # отрезать от новостного сообщения начало в $numwords слов my ($str, $nw) = @_; my $ret; $str =~ s!<p(.*?)>! <p$1>!i; $str =~ s!<br>! <br>!i; $str =~ s!<div(.*?)>! <div$1>!i; $str =~ s!<(/*strong)>!%%$1%%!gi; $str =~ s!<(/*)b>!%%$1strong%%!gi; $str =~ s!<img (.+?)>!%%img $1%%!i; $str =~ s/(<(?=!--)([^>]|\\n)*--(?=>)>)//ig; $str =~ s/|(<\\/?([^>]|\\n)*>)//g; $str =~ s/&nbsp;/ /g; $str =~ s/\\s+/ /g; $str =~ s!%%(/*strong)%%!<$1>!gi; $str =~ s!%%img (.+?)%%!<img $1>!i; my @a = split(/\\s/, $str); if ($#a > $nw) { $ret = join(\' \', splice(@a, 0, $nw)) . qq{<b> . . .</b>}; } else { $ret = $str; } if (($ret =~ m!<strong>!) && ($ret !~ m!</strong>!)) { $ret .= "</strong>"; } return $ret; } ###################################################################### sub round { # округлить значение my $i = shift; return $i - int($i) < 0.5 ? int($i) : int($i)+1; } ###################################################################### sub rss_expand_img_url { # разворачивает URL картинки для RSS my ($u1, $u2, $u3) = @_; return "<img $u1"."src=\\"http://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_expand_hrf_url { # разворачивает URL ссылки для RSS my ($u1, $u2, $u3) = @_; return "<a $u1"."href=\\"https://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_clear_html_to_xml { # причесывает страницу по правилам XML my $txt = shift; $txt =~ s/<img (.*?)src="(.+?)"(.*?)>/rss_expand_img_url($1,$2,$3)/ige; $txt =~ s/<a (.*?)href="(.+?)"(.*?)>/rss_expand_hrf_url($1,$2,$3)/ige; $txt =~ s/&nbsp;/ /g; $txt =~ s/\\s+/ /g; $txt =~ s/&/&amp;/g; $txt =~ s/</&lt;/gi; return $txt; } ###################################################################### sub get_root_category { # для текущего раздела (что в последнем элементе массива @treewalk) ищет предка, у которого родитель = 4 if (@treewalk) { if (@treewalk[scalar(@treewalk)-1]->[0] == 4) { return @treewalk[scalar(@treewalk)-2]->[1]; } else { return @treewalk[scalar(@treewalk)-1]->[1]; } } else { return ""; } } ###################################################################### sub send_mail_smtp { # ($host, $from, $to, $body) my ($_host, $_from, $_to, $_xbody) = @_; $_xbody = "To: $_to\\n$_xbody"; my $smtp = Net::SMTP->new($_host, Hello => \'mail.arhcity.ru\', Timeout => 30); $smtp->mail($_from); $smtp->to($_to); $smtp->data(); $smtp->datasend($_xbody); $smtp->dataend(); $smtp->quit; } ###################################################################### sub get_cookie { # возвращает значение куки по ключу (см. \\asp\\admin\\lib\\adminlib.js) my $name = shift; my $cook = $SERVER->{HTTP_COOKIE}; my @arr = split(/;\\s*/, $cook); my %ck = (); foreach my $c (@arr) { my ($k, $v) = split(/=/, $c); $ck{$k} = $v; } return $ck{$name}; } ###################################################################### sub random_str { # возвращает строку указанной длинны (или 5) из случайных символов my $len = shift || 5; my $c = \'0123456789abcdefghijklmnopqrstuvwxyz\'; my $l = length($c); my $s = \'\'; for (1 .. $len) { $s .= substr($c, int(rand()*$l), 1); } return $s; } ###################################################################### sub check_body_style { # ( body ) my $body = shift; my (@cb_arr, @ret_txt) = (); @cb_arr = (); @cb_arr = $body =~ m!<(img|a).* (src|href)="data:image/(gif|png|jpeg);base64,(\\S+)"!sg; push(@ret_txt, "&bull; Недопустимое применение ссылок формата \\"data:image\\" (".(scalar(@cb_arr)/4)." раз.)") if (@cb_arr > 0); @cb_arr = (); @cb_arr = $body =~ m/<w:LsdException/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'LsdException\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/<w:WordDocument>/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'WordDocument\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/text-indent:27\\.0pt|class="MsoNormal"|tab-stops:list -9\\.0pt|mso-layout-grid-align:/sg; push(@ret_txt, "&bull; В тексте присутствуют инлайн-стили от Microsoft Word (".scalar(@cb_arr)." раз.)") if (@cb_arr > 4); @cb_arr = (); @cb_arr = $body =~ m/style="font-family: \'Times New Roman\'/sg; push(@ret_txt, "&bull; Слишком частое использование шрифта \'Times New Roman\' (".scalar(@cb_arr)." раз.)") if (@cb_arr > 5); @cb_arr = (); @cb_arr = $body =~ m/<span style="color: .+?;">|<span style="background-color: rgb(255, 255, 255);">/sg; push(@ret_txt, "&bull; Частое/неуместное использование цветового выделения (".scalar(@cb_arr)." раз.)") if (@cb_arr > 8); if (@ret_txt) { return join("<br>\\n", @ret_txt); } else { return 0; } } ###################################################################### sub meta_og_tags { # возвращает "Open Graph" тэги для страницы my ($sid, $pid) = @_; my $pageheader = $section{secname}; $pageheader = "Городские новости" if ($sid == 0); # https://ruogp.me/ - Протокол Open Graph my $r = \'\'; $r .= qq{<meta property="og:site_name" content="Администрация города Архангельска" />\\n}; $r .= qq{<meta property="og:url" content="http://arhcity.ru/?page=$sid/$pid" />\\n}; $r .= qq{<meta property="og:title" content="$pageheader" />\\n}; $r .= qq{<meta property="og:description" content="$document{pagename}" />\\n}; $r .= qq{<meta property="og:image" content="http://arhcity.ru/pic/og-image-arhcity.jpg" />\\n}; if ($section{sectype} eq \'table\') { my $_r = \'\'; my $c = 0; my @og_image = $document{pagebody} =~ m!<img src="(.+?)" .+/>!g; foreach my $i (@og_image) { $i =~ s!http://.+?\\.ru!!g; $_r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; $c++; } if ($c > 5) { # если картинок на странице много ( >5 ) - показываем только первую my $i = @og_image[0]; $i =~ s!http://.+?\\.ru!!g; $r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; } else { $r = $_r; } } return $r; } ###################################################################### sub gen_int_EO { # (number) # возвращает случайное чётное/нечётное число в интервале 0..number в зависимости от чётности number my $n = shift; my $r = int(rand() * $n); if ($n % 2 == 0) { $r++ if ($r % 2 == 1); } else { $r++ if ($r % 2 == 0); } return $r; } ###################################################################### sub update_msie_css { # внедряем в default.css значения переменных из colors.css и создаём default-ie.css my $ret = 0; my %vars = (); my $default_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default.css"; my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; my $default_ie_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default-ie.css"; my ($t_default_css) = (stat($default_css_fn))[9]; my ($t_colors_css) = (stat($colors_css_fn))[9]; my ($t_default_ie_css) = (stat($default_ie_css_fn))[9]; if (($t_default_css > $t_default_ie_css) || ($t_colors_css > $t_default_ie_css)) { open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); open(FS, "< $default_css_fn") || die "Can\'t open $default_css_fn, $!\\n"; open(FO, "> $default_ie_css_fn") || die "Can\'t open $default_ie_css_fn, $!\\n"; while (my $l = <FS>) { next if ($l =~ m/colors.css/); $l =~ s/(var\\((--.+?)\\))/exists($vars{$2})?$vars{$2}:\'none\'/gsex; print FO $l; } close(FO); close(FS); } $ret = 1 if ((stat($default_ie_css_fn))[7] > 0); # if filesize $default_ie_css_fn > 0 - file OK. return $ret; } ###################################################################### ## XML subroutines ################################################### ###################################################################### # see http://www.arhcity.ru/1.asp # ###################################################################### sub ipcms::button { my ($args, $html) = @_; my ($ico, $spacer); if (( $args->{ico}) && ( $args->{txt})) { $spacer = \'&nbsp;\'; } if ((!$args->{ico}) && ( $args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="1" height="16">\'; } if (( $args->{ico}) && (!$args->{txt})) { $spacer = \'\'; } if ((!$args->{ico}) && (!$args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="16" height="16">\'; } if ($args->{ico}) { $ico = qq{<img src="$args->{ico}" width="16" height="16">}; } print qq{<a href="$args->{url}"><div class="shbutton">}.$ico.$spacer.$args->{txt}.qq{</div></a>}; } ###################################################################### sub ipcms::panel { my ($args, $html) = @_; my ($o_style, $style); $o_style = $args->{style} if ($args->{style}); $style = qq{ style="$o_style"} if ($o_style); print qq{<div class="border_area"$style>$html<br>}; print_dump($args); print qq{</div>\\n}; } ;; sub exit { $main::Response->End(); } ;; no lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; 1;' called at /usr/local/share/perl5/Apache/ASP/GlobalASA.pm line 122 Apache::ASP::GlobalASA::new('Apache::ASP=HASH(0x562e3465c280)') called at /usr/local/share/perl5/Apache/ASP.pm line 389 Apache::ASP::new('Apache::ASP', 'Apache2::RequestRec=SCALAR(0x562e342fd2a8)', '/var/www/HDD2/mc.arhcity.ru/asp/index.asp') called at /usr/local/share/perl5/Apache/ASP.pm line 184 Apache::ASP::handler('Apache2::RequestRec=SCALAR(0x562e342fd2a8)') called at /usr/lib64/perl5/IO/Socket.pm line 18 eval {...} called at /usr/lib64/perl5/IO/Socket.pm line 18 Compilation failed in require at /usr/share/perl5/Net/SMTP.pm line 15. at /usr/share/perl5/Net/SMTP.pm line 15. Net::SMTP::BEGIN() called at /usr/share/perl5/Net/SMTP.pm line 15 eval {...} called at /usr/share/perl5/Net/SMTP.pm line 15 require Net/SMTP.pm called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax::BEGIN() called at /usr/share/perl5/Net/SMTP.pm line 15 eval {...} called at /usr/share/perl5/Net/SMTP.pm line 15 eval ' #line 1 /var/www/HDD2/mc.arhcity.ru/asa/global.asa package Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax; ;; use strict ;; use vars qw($Application $Session $Response $Server $Request); ;; use lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; #!/usr/bin/perl use Time::HiRes qw(gettimeofday tv_interval); use Apache::DBI; # automatic persistent database connections use DBI; use HTTP::Date; use Digest::SHA1 qw(sha1_hex sha1_base64); use Socket; use URI::UTF8::Punycode; use APR::UUID; use Text::Iconv; use Net::SMTP; # when PerlSetVar UseStrict setting on, need to declare # global variables with "use vars" ################################################################## # declare global variables use vars (\'$db\', # database interface \'$FORM\', # form data, method POST \'$QUERY\', # form data, method GET \'$POST\', # unformat form data, method POST \'$SERVER\', # server variables \'$localnet\', # access from local network \'$have_inet\', # access to internet \'$remoteaddr\', # remote IP address \'$useragent\', # UserAgent () \'$site_admin\', # Enable extra functions for site admins \'$logged_in\', # admin access by session \'$lc_logged_in\', # private cabinet access by session \'$servername\', # name of server \'$addrubrics\', # additional menu "rubrics" \'$tpl_dir\', # html template directory \'$godaccess\', # GOD access \'$hires_time\', # time generation of page ############################# \'%userinfo\', # entrie user data (hash) \'%section\', # entrie section data (hash) \'%document\', # entrie document data (hash) ############################# \'@treewalk\', # walking from leaf to root = ([$node, $secname, $sectpl]) \'%mod_params\', # parameters for plugins \'$zx_counter\', # counter for all unique repitable operations \'$site_url\', # url to site \'$site_path\', # path to site location \'$blindview\', # blind vew mode \'%CSS_vars\', # CSS variables ); ################################################################## my $host = \'localhost\'; my $db_name = \'ipcms3\'; my $dsn = "DBI:mysql:database=$db_name:host=$host"; my $username = \'root\'; my $password = \'\'; ################################################################## my $log_file; my $uploaddir; my $admin_dir = "/admin/"; my $lcab = "/lc/"; # list of datastore fields for separate \'_ex\' and non \'_ex\' fields my @doc_fields = qw(sid pid userid url pagename pagebody pagedate pagemodify pageorder sh_hdr sh_dir sh_nav sh_tab docstatus rating1 rating2); # at the begining of the page execution sub Script_OnStart { $hires_time = [gettimeofday]; $Response->Include("site_setup.asp"); # get default values for current site $log_file = "$site_path/datafiles/ipcms3.log"; $uploaddir = "$site_path/asp/data"; $Response->{\'ContentType\'} = "text/html"; $Response->{\'Charset\'} = "Windows-1251"; # $Response->{\'Expires\'} = 0; # page expired after NN seconds from download. # $Response->{\'Last-Modified:\'} = time2str(time-1); $FORM = $Request->Form(); $QUERY = $Request->QueryString(); # $POST = $Request->BinaryRead($Request->ServerVariables(\'CONTENT_LENGTH\')); # for debug $SERVER = $Request->ServerVariables(); $remoteaddr = $SERVER->{\'REMOTE_ADDR\'}; $servername = $SERVER->{\'SERVER_NAME\'}; $tpl_dir = $SERVER->{\'DOCUMENT_ROOT\'}."/templates"; $blindview = get_cookie("blindview") || 0; %userinfo = (); %section = (); %document = (); $addrubrics = \'\'; $site_admin = 0; $logged_in = 0; $godaccess = 0; $localnet = 0; $have_inet = 0; @treewalk = (); $zx_counter = 0; # Global Redirect Block... if ($servername eq \'arhcity.ru\') { $Response->Redirect("http://$site_url"); } if ($servername eq \'arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } if ($servername eq \'www.arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } # if ($SERVER->{HTTPS} ne \'on\') { # $Response->Redirect("https://www.arhcity.ru/?$SERVER->{QUERY_STRING}"); # } my $ic = Text::Iconv->new("UTF-8", "WINDOWS-1251"); my @r = (); foreach my $i (split(/\\./, $servername)) { if ($i =~ m/^xn--/) { push(@r, puny_dec($i)); } else { push(@r, $i); } } $servername = join(\'.\', @r); $servername = $ic->convert($servername); if ($SERVER->{HTTP_USER_AGENT} =~ m/edge/i) { $useragent = \'edge\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/chrome/i) { $useragent = \'chrome\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/webkit/i) { $useragent = \'safari\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/opera/i) { $useragent = \'opera\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/msie/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/trident/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/mozilla/i) { $useragent = \'mozilla\' } else { $useragent = \'unknown\'; } if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { # read CSS color variables for replace in html code (MSIE/Edge not support CSS vars); my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $CSS_vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); } if (($remoteaddr =~ m/^192\\.168\\./) || ($remoteaddr eq \'212.14.176.38\') || ($remoteaddr eq \'212.14.176.39\') || ($remoteaddr eq \'212.14.176.46\') || ($remoteaddr eq \'212.14.176.40\') || ($remoteaddr eq \'212.14.176.41\') || ($remoteaddr eq \'212.14.176.44\') || ($remoteaddr eq \'195.239.119.234\') # Городской центр гражданской защиты ) { $localnet = 1; } if (($localnet) && ( # Enable extra functions for site admins ($remoteaddr eq \'192.168.1.84\') || # GaidukAV ($remoteaddr eq \'192.168.1.44\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.45\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.46\' ) || # KorzhevDP ($remoteaddr eq \'192.168.51.144\') || # VishnyakovNS ($remoteaddr eq \'192.168.1.102\') || # EkimovKS v.1 ($remoteaddr eq \'192.168.1.110\') || # EkimovKS v.2 ($remoteaddr eq \'192.168.51.42\')) # EkimovKS v.3 ) { $site_admin = 1; } # connect to database $db = DBI->connect($dsn, $username, $password); if (! $db) { print "<p>Database server not responding.<br>Try later.</p>\\n"; $Response->End(); } # ONLY FOR RUSSIAN for MySQL !!! $db->do("set names cp1251"); if ($localnet) { # enable/disable outside scripts on site for local users without inet. ($have_inet) = getonerec("select count(ip) from squid_list where ip = \'$remoteaddr\'"); } else { $have_inet = 1; } # ------------------------------------------------------------ # $have_inet = 0; # !!! disable external scripts on site !!! # ------------------------------------------------------------ if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # !!! admin mode !!! $logged_in = 0; my $uname = $Session->{Authentication}; my $topframe = 0; if ($uname) { # logged in $logged_in = 1; $Session->{top_frame} = 0; my $adm_lib = $admin_dir . "lib/"; if ($SERVER->{\'REQUEST_URI\'} =~ m/$adm_lib/) { # read user info %userinfo = get_user_info($uname); $godaccess = 1 if ($userinfo{god} eq \'Y\'); if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no header } else { $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; } if ($SERVER->{\'REQUEST_URI\'} =~ m/(section.asp)|(page.asp)|(journal.asp)|(admin.asp)/i) { $Response->Include("page_autologoff.asp"); } } } else { # not logged in $topframe = $Session->{top_frame}; if (!$topframe) { my $location = "top.location.href=\'/admin/?t=".time()."\'"; print qq{<script>$location</script>}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n</body>\\n</html>\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with <style></style> definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "<pre>",Dumper(@_),"</pre>\\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n<script>\\n$location\\n</script".">\\n"; } ###################################################################### sub navigator { # отобразить навигатор (путь с корня до страницы) my @a = (\'<a href="/">Начало</a>\'); # if $sid in internal section (#6) - don\'t show any information my $rootsec = @treewalk[$#treewalk]; if ( (!$localnet) && ($rootsec->[0] == 6) ) { # ... } else { foreach my $i (reverse @treewalk) { push(@a, qq{<a href="/?page=$i->[0]/0">$i->[1]</a>}) if ($i->[0] > 0); } } return join(\' <span style="color:red"><img src="/pic/navar.gif" align="baseline"></span> \', @a); } ###################################################################### sub get_config_value { my $varname = shift; my ($varvalue) = getonerec("select varvalue from options where varname = \'$varname\'"); return $varvalue; } ###################################################################### sub store_config_value { my ($varname, $varvalue) = @_; my $query = "update options set varvalue=? where varname=?"; my $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($varvalue, $varname) || print $db->errstr, ", query:[$query]<br>\\n"; $st->finish; } ###################################################################### sub get_user_info { # прочитать информацию о зарегистрированном пользователе (по логину) # return hash my $user = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where username = \'$user\'"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub get_user_id_info { # прочитать информацию о зарегистрированном пользователе (по id) # return hash my $user_id = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where id = $user_id"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub make_pw_hash { # (password) # Создание уникального хэша по паролю my $password = shift; my $letts = \'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\'; my $lettl = length($letts); my $salt = \'\'; $password = substr($password, 0, 32) if (length($password) > 32); # limit password length for my $i (1 .. 5) { $salt .= substr($letts, int(rand() * $lettl), 1); } return $salt.sha1_base64($salt.$password); } ###################################################################### sub check_pw_hash { # (password, pwd_hash) # проверка на соответствие хэша и пароля my $password = shift; my $pw_hash = shift; my $salt = substr($pw_hash, 0, 5); $password = substr($password, 0, 32) if (length($password) > 32); # limit password length return (substr($pw_hash, 5) eq sha1_base64($salt.$password)); } ###################################################################### sub check_auth { # (user, password) # проверка авторизации my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'N\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub check_auth_lc { # (user, password) # проверка авторизации lcab my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'Y\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub get_inherit_tpl { # (sid) # найти имя наследуемого шаблона дизайна my $tpn = "default"; my $tpn2 = \'\'; @treewalk = tree_walk(shift); foreach my $i (reverse(@treewalk)) { if ($i->[2] ne \'\') { $tpn2 = $tpn; $tpn = $i->[2]; } } return ($tpn, $tpn2); } ###################################################################### sub get_tpl_list { # пполучить список доступных шаблонов дизайна my ($c, @ret) = 0; opendir(D, $tpl_dir); while (my $d = readdir(D)) { if ($d =~ m/^(.+)\\.asp$/) { push(@ret, $1); } } closedir(D); return sort @ret; } ###################################################################### sub tree_walk { # ($sid) # пройтись по дереву от указанного раздела до корня, записать в массив ($node, $secname, $sectpl) my ($node, $pnode, $secname, $sectpl, @tw) = shift; my $c = 0; while ($node != 0) { ($node, $pnode, $secname, $sectpl) = getonerec("select sid,secparent,secname,sectpl from section where sid=$node"); push(@tw, ([$node, $secname, $sectpl])); $node = $pnode; $c++; if ($c > 20) { # если очень большое количество итераций - значит в базе ошибка. my $t = \'\'; foreach (@tw) { $t .= \' \'.$_->[0]; } print error("В базе данных ошибка! Возможно зацикленная рекурсия. Срочно обратитесь к администратору.<br>tree_walk: [$t]"); last; } } return @tw; } ###################################################################### sub getonerec { # (query) # прочитать одну запись из базы my ($query, $st, @row) = shift; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]<br>\\n"; $st->execute() || print $db->errstr, ", Q:[$query]<br>\\n"; @row = $st->fetchrow_array; $st->finish; return @row; } ###################################################################### sub get_sql_list { # прочитать список из базы # return @arr = (\'a1\',\'b1\',\'c1\'); my $q = shift; my ($s,@r,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { push(@ret, $r[0]); } $s->finish; return @ret; } ###################################################################### sub get_sql_arr { # прочитать список списков (таблицу) из базы # return @arr = ( [\'a1\',\'a2\'], [\'b1\',\'b2\'], [\'c1\',\'c2\'] ); my $q = shift; my ($s,$rf,@r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { @rt = (); for my $i (0 .. scalar(@r)-1) { $rt[0][$i] = $r[$i]; } push(@ret, @rt); } $s->finish; return @ret; } ###################################################################### sub get_sql_arhash { # (query) # прочитать список хэшей (таблицу с именованными столбцами) из базы # return array of hashes my $q = shift; my ($s,$rf,$r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { push(@ret, $r); } $s->finish; return @ret; } ###################################################################### sub input_text { # ($name, $style, $value) # создать текстовое поле ввода my ($name, $style, $value) = @_; $style .= qq{ id="id$name"} if ($name); my $ret = qq{<input type="text" name="$name" value="$value" $style>}; return $ret; } ###################################################################### sub input_checkbox_1Y { # ($name, $style, $value, $label) # создать поле ввода чекбокс (одиночный) my ($name, $style, $value, $label) = @_; my $ret = ""; my $checked = (($value eq "Y") || ($value eq "on")) ? "checked" : ""; $zx_counter++; $ret = qq{<input type="checkbox" name="$name" id="id$zx_counter$name" $checked $style>&nbsp;<label for="id$zx_counter$name">$label</label>}; return $ret; } ###################################################################### sub input_radio { # ($name, $style, $js, $br, $checked, %values) # создать поле ввода радиоботтон (группу) my ($name, $style, $js, $br, $checked, %values) = @_; my $ret; my $j = ""; foreach my $i (sort keys %values) { if ($js ne \'\') { $j = qq{onclick="$js(\'$i\');"}; } my $checkstr = ($checked eq $i) ? "checked" : ""; $ret .= qq{<input type="radio" name="$name" id="$i" value="$i" $checkstr $style $j>\\n<label for="$i">$values{$i}</label>$br\\n}; } return $ret; } ###################################################################### sub input_textarea { # ($name, $style, $value) # создать поле тексареа my ($name, $style, $value) = @_; my $ret = qq{<textarea name="$name" $style>$value</textarea>}; return $ret; } ###################################################################### sub input_texteditor { # ($name, $imgdir, $value) # создать текстовый редактор на базе FCKeditor my ($name, $imgdir, $value) = @_; my $te = $Response->TrapInclude("page_fckeditor.asp", $name, $imgdir, $value); return $$te; } ###################################################################### sub input_list_arr { # ($name, $style, $currvalue, @arr) # создать поле список из 2d массива, с отключением отображения id # @arr = ( [1,\'a1\'], [2,\'a2\'], [3,\'a3\'] ); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); my $nonum = 0; my $size = qq{size="1"}; $size = $1 if ($style =~ s/(size=["\']*\\d+["\']*)//i); $nonum = 1 if ($style =~ s/nonum//i); $style .= qq{ id="id$name"} if ($name); $ret = qq{<select name="$name" $size $style>\\n}; for my $i (0 .. scalar(@arr)-1) { $sel = \'\'; if ($currvalue =~ m/^\\d+$/) { $sel = "selected" if ($arr[$i][0] == $currvalue); } else { $sel = "selected" if ($arr[$i][0] eq $currvalue); } if ($nonum) { $ret .= qq{<option $sel value="$arr[$i][0]">$arr[$i][1]</option>\\n}; } else { $ret .= qq{<option $sel value="$arr[$i][0]">[$arr[$i][0]] $arr[$i][1]</option>\\n}; } } $ret .= "</select>"; return $ret; } ###################################################################### sub input_list_arr_X1 { # ($name, $style, $currvalue, @arr) # создать поле список из 1d массива # @arr = (\'a1\',\'a2\',\'a3\'); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); $style .= qq{ id="id$name"} if ($name); $ret = "<select name=\\"$name\\" size=\\"1\\" $style>\\n"; foreach my $i (@arr) { if ($i eq $currvalue) { $sel = "selected"; } else { $sel = ""; } $ret .= qq{<option $sel value="$i">$i</option>\\n}; } $ret .= "</select>"; return $ret; } ###################################################################### sub check_acc { # ($sid, $acc_letters) # проверка прав доступа к разделу my ($sid, $acs) = @_; return 1 if ($godaccess); if ($sid =~ m/^\\d+$/) { #my @rghts = get_sql_list("select rights from usersacc where userid=$userinfo{id} and sid=$sid"); my $query = "select usersacc.rights from users inner join usersacc on (users.id = usersacc.userid) where users.enable = \'Y\' and users.id = $userinfo{id} and usersacc.sid = $sid"; my @rghts = get_sql_list($query); my $rights = join(\'\', @rghts); foreach my $ac (split(\'\', $acs)) { return 1 if ($rights =~ m/$ac/); } return 0; } return 0; } ###################################################################### sub tablist { # $sid, $pid, \'tabsheet\', \'focus\', startN, (array of names) # создание панели с закладками (используется в page.asp и section.asp) my ($sid, $pid, $tabsheet_name, $focus_name, $start_page, @pages) = @_; my $pagenum = scalar(@pages)-1; my ($out,$focus1,$focus2); =pod =head1 Параметры вызова: tablist($sid, $pid, \'tabsheet\', \'focus\', startN, (array of names)); =item $sid, $pid Номера раздела и страницы Если номер раздела < 0 - закладка со ссылкой на дерево объектов НЕ отображается. =item \'tabsheet\' HTML Идентификатор панели с табами =item startN Номер закладки, которую нужно открыть при старте страницы Для этого в запросе должен присутствовать параметр "ctsh=N" где N - номер закладки =item \'focus\' Идентификатор HTML объекта для установки фокуса при открытии каждой из закладок =item (array of names) Список строк, являющихся текстом на закладках =head1 Пример реализации панели с табами: <style> #tabsheet0 {display:none} /* в некоторых версяиях браузеров из за ошибки надо комментировать эту строку */ #tabsheet1 {display:none} #tabsheet2 {display:none} .tabsheet { ... } </style> <#% my @tabs = ( \'<img src="/pic/page1.png"> Page One\', \'<img src="/pic/page2.png"> Page Two\', \'<img src="/pic/page3.png"> Page Three\' ); my $ctsh; $ctsh = $FORM->{ctsh}; $ctsh = $QUERY->{ctsh} if ($ctsh eq \'\'); print tablist(-1, \'\', \'tabsheet\', \'fcs\', ($ctsh =~ m/[012]/)?$ctsh:0, @tabs); %#> <div class="tabarea"> <table border="0" width="100%" cellpadding="8" cellspacing="0"><tr><td> <div id="tabsheet0" class="tabsheet">Page 1<br><input type="text" id="fcs0"></div> <div id="tabsheet1" class="tabsheet">Page 2<br><input type="text" id="fcs1"></div> <div id="tabsheet2" class="tabsheet">Page 3<br><input type="text" id="fcs2"></div> </td></tr></table> </div> =cut my $css = qq[ <style> #tablist { padding: 3px 0 3px 6px; margin-left: 0; font: 13px Tahoma; /* line-height: 16px; */ white-space: nowrap; } #tablist li { list-style: none; margin: 0; display: inline; white-space: nowrap; } #tablist li a { color: #555; padding: 3px 6px; margin-left: 3px; border: 1px solid #888; border-bottom: none; background: #ddd; text-decoration: none; font-weight: normal; border-top-left-radius: 6px; border-top-right-radius: 6px; } </style> ]; my $javascript = qq[ <script language="JavaScript"> window.onload = function(){ showTab($start_page); } function showTab(tabnum) { for (i = 0; i <= $pagenum; i++) { document.getElementById(\'$tabsheet_name\'+i).style.display = \'none\'; tln = document.getElementById(\'xtl\'+i); tln.style.color = \'#555\'; tln.style.background = \'#ddd\'; tln.style.borderBottom = \'1px solid #888\'; } var tsheet = document.getElementById(\'$tabsheet_name\'+tabnum); var fcname = document.getElementById(\'$focus_name\'+tabnum); var tln = document.getElementById(\'xtl\'+tabnum); if (tsheet) { tsheet.style.display = \'block\'; } if (fcname) { fcname.focus(); } if (tln) { tln.style.color = \'#000\'; tln.style.background = \'white\'; tln.style.borderBottom = \'1px solid white\'; tln.style.backgroundImage = \'url(/admin/pic/tab_bg.gif)\'; } } </script]; # See ...Perl\\site\\lib\\Apache\\ASP\\GlobalASA.pm, lines 91,92... $out .= $css.$javascript.">\\n"; # stupid bug... $out .= qq{\\n<ul id="tablist" style="margin-bottom:0px;">\\n}; if ($sid > 0) { # отображение закладки со ссылкой на дерево объектов $out .= qq{ <li><a href="treejx.asp?sid=$sid&pid=$pid" style="padding-left:0;margin-left:0;background-color:#20a020;color:#c0ffc0;text-decoration:none" target="treeframe">&nbsp;<acronym title="Отобразить курсор на дереве объектов"><img src="/admin/pic/tree/node-tree.png" class="trico">&nbsp;$sid/$pid&nbsp;</acronym></a></li>\\n}; } for(my $i=0; $i<=$pagenum; $i++) { $pages[0] = qq{<span style="color:blue">$pages[0]</span>} if (($section{sectype} eq \'asp\') || ($sid == 0)); $out .= qq{ <li><a href="#$i" id="xtl$i" onclick="showTab($i)">$pages[$i]</a></li>\\n}; } $out .= qq{</ul>\\n}; return $out; } ####################################################################### sub get_indexgroup_str { # (index_name) # получить строку списка разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return $idx; } ####################################################################### sub get_indexgroup_lst { # (index_name) # получить список разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return split(/,\\s*/, $idx); } ####################################################################### sub exist_in_indexgroup { # ($index_name, $value) # проверить наличие $value в списке разделов по имени my ($index_name, $value) = @_; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return exist_in_list($value, split(/,\\s*/, $idx)); } ###################################################################### sub recalctree { # ($sid) # получить список всех подчиненных разделов от указанного my $sl = shift; $sl =~ s/\\D+/,/g; my @srvindex = (); my ($q, $s, $r); $q = "select sid from section order by sid"; $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { my @tw = (); @treewalk = &tree_walk($r->{sid}); foreach my $item (reverse @treewalk) { push(@tw, $item->[0]); } my %union = (); my %isect = (); # объединение и пересечение множеств @tw и "$sl", результат в %union и %isect foreach my $e (@tw, split(\',\', $sl)) { $union{$e}++ && $isect{$e}++ } push(@srvindex, $r->{sid}) if (scalar(keys %isect)); } $s->finish; return @srvindex; } ####################################################################### sub autorecalctree { # Обновление индексных групп при изменении иерархии разделов my $visual = shift; my ($q1, $s1, $r1); my ($q2, $s2, $r2); print qq{<div id="autoupdate" style="padding-top:10px;">Обновление индексных групп : } if ($visual); $q1 = "select id,slist from srvindex order by id desc"; $s1 = $db->prepare($q1) || print $db->errstr, ", query:[$q1]<br>\\n"; $s1->execute() || print $db->errstr, ", query:[$q1]<br>\\n"; while ( $r1 = $s1->fetchrow_hashref ) { print qq{<span style="background-color:blue;color:white">&nbsp;$r1->{id}&nbsp;</span>&nbsp;} if ($visual); $Response->Flush() if ($visual); # anti timeout solution my $flist = join(\',\', recalctree($r1->{slist})); $q2 = "update srvindex set flist=? where id=$r1->{id}"; $s2 = $db->prepare($q2) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->execute($flist) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->finish; } $s1->finish; print qq{\\n</div>\\n<style>#autoupdate {display:none} </style>\\n} if ($visual); } ####################################################################### sub check_for_secdel { # (sid) # проверка возможности удаления раздела my ($sid) = @_; my @cd_msg = (); my ($cs, $cp, $cf) = (0, 0, 0); my $filedir = "$uploaddir/$sid"; # считаем количество подразделов ($cs) = getonerec("select count(sid) from section where secparent = $sid"); push(@cd_msg, "Разделов: <span style=\'color:red\'>$cs</span>") if ($cs); # считаем количество документов в разделе ($cp) = getonerec("select count(pid) from documents where sid = $sid"); push(@cd_msg, "Страниц: <span style=\'color:red\'>$cp</span>") if ($cp); # считаем количество файлов в разделе if (opendir(D, $filedir)) { my @rm_dir = readdir(D); closedir(D); $cf = scalar(@rm_dir); # уменьшаем $cf из за служебных папок: \'.\' и \'..\' foreach my $d (@rm_dir) { $cf-- if ($d =~ m/^\\.+$/); } } push(@cd_msg, "Файлов: <span style=\'color:red\'>$cf</span>") if ($cf); return @cd_msg; } ###################################################################### sub get_section { # (sid) # прочитать информацию о разделе # return hash my ($sid) = @_; my (%ret, $query, $st, $row) = (); if ($sid > 0) { $query = "select * from section where sid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; } return %ret; } ###################################################################### sub get_document { # (sid, pid) # прочитать документ # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); $query = "select * from documents where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; $st->finish; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } return %ret; } ###################################################################### sub get_document_ex { # (sid, pid) # прочитать документ с расширенными полями # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); %ret = get_document($sid, $pid); $query = "select field,value from documents_ex where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { $ret{$row->{field}} = $row->{value}; } $st->finish; return %ret; } ###################################################################### sub get_sec_documents { # (sid, \'body\') # прочитать все документы раздела (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body) = @_; my (@ret, $query, $st, $row, $b) = (); $b = \'pagebody,\' if ($body); my $fields = "sid,pid,userid,url,pagename,".$b."pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus"; $query = "select $fields from documents where sid=? order by pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; return @ret; } ###################################################################### sub get_sec_documents_ex { # (sid, body, x_where) # прочитать все документы раздела с расширенными полями (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body, $x_where) = @_; my (@ret, @ret_ex, $query, $st, $row, $b) = (); $b = \'documents.pagebody,\' if ($body); my $fields = " documents.sid, documents.pid, documents.userid, documents.url, documents.pagename, $b documents.pagedate, documents.pagemodify, documents.pageorder, documents.sh_hdr, documents.sh_dir, documents.sh_nav, documents.sh_tab, documents.docstatus, documents_ex.field, documents_ex.value"; $query = "select $fields from documents left outer join documents_ex on (documents_ex.sid = documents.sid) and (documents_ex.pid = documents.pid) where documents.sid = $sid"; $query = "$query and ($x_where)" if ($x_where); # open(F, ">>$site_path/asa/q.log"); # print F "get_sec_documents_ex: $query\\n\\n"; # close(F); $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute() || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; # получили массив @ret с дублями строк для полей из documents my %h = (); foreach my $i (@ret) { # чтобы избавится от дублей пихаем строки в хэш, где ключ = \'sid.pid\' if (!defined($h{"$i->{sid}.$i->{pid}"})) { $h{"$i->{sid}.$i->{pid}"} = { \'sid\' => $i->{\'sid\'}, \'pid\' => $i->{\'pid\'}, \'userid\' => $i->{\'userid\'}, \'url\' => $i->{\'url\'}, \'pagename\' => $i->{\'pagename\'}, \'pagedate\' => $i->{\'pagedate\'}, \'pagemodify\' => $i->{\'pagemodify\'}, \'pageorder\' => $i->{\'pageorder\'}, \'sh_hdr\' => $i->{\'sh_hdr\'}, \'sh_dir\' => $i->{\'sh_dir\'}, \'sh_nav\' => $i->{\'sh_nav\'}, \'sh_tab\' => $i->{\'sh_tab\'}, \'docstatus\' => $i->{\'docstatus\'}, $i->{\'field\'} => $i->{\'value\'}, }; } else { # в случае сущесвования такой же строки в хэше - добавляем очередное поле из documents_ex $h{"$i->{sid}.$i->{pid}"}->{$i->{\'field\'}} = $i->{\'value\'}; } } @ret = (); # перекидываем всё из хэша в массив foreach my $i (keys %h) { push(@ret, $h{$i}); } return @ret; } ###################################################################### sub create_document { # (sid, userid, hash_fields) # создать документ в указанном разделе my ($sid, $userid, %fields) = @_; my ($pid, $query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # search new $pid for $sid my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $pid++; # set default values for new document $fields{pageorder} = $pid * 10; # insert new fields of document $query = "insert into documents (sid,pid,userid,url,pagename,pagebody,pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'create_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_document_ex { # (sid, userid, hash_fields) # создать документ с расширенными полями в указанном разделе my ($sid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { create_document($sid, $userid, %fields); my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $fields{pagebody} = \'\'; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'create_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document { # ($sid, $pid, $userid) # удалить документ my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document_ex { # ($sid, $pid, $userid) # удалить документ с расширенными полями my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); my %fields_ex = get_document_ex($sid, $pid); $query = "delete from documents_ex where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = \'\'; foreach my $i (keys %fields_ex) { $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'delete_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_section { # (sid) # удалить раздел my ($sid) = @_; my ($st, $query); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { $query = "delete from section where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); # remove rights for deleted section $query = "delete from usersacc where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document { # (sid, pid, userid, hash_fields) # заменить документ my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # update fields of document $query = "update documents set userid=?,url=?,pagename=?,pagebody=?,pagedate=?,pagemodify=?,pageorder=?,sh_hdr=?,sh_dir=?,sh_nav=?,sh_tab=?,docstatus=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'replace_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document_ex { # (sid, pid, userid, hash_fields) # заменить документ с расширенными полями my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { replace_document($sid, $pid, $userid, %fields); $fields{pagebody} = \'\'; # delete \'_ex\' fields in documents_ex $query = "delete from documents_ex where sid = $sid and pid = $pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]== $fields_ex{$i}\\n"; } journaldata(\'replace_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_section { # (hash_fields) # создать раздел my (%fields) = @_; my ($st, $sid, $query); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($secorder) = getonerec("select max(secorder) from section where secparent=$FORM->{secparent}"); $secorder = $secorder + 10; $fields{sectype} = $fields{sectype} || \'table\'; $fields{sorttype} = $fields{sorttype} || \'az\'; # insert record of section $query = "insert into section (secparent,secname,secdescr,sectype,plug_view,plug_admn,plug_ico,startpage,sorttype,secorder,sh_nav,sh_dir,sh_hdr) values (?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secparent}, $fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, ($fields{sectype} eq \'table\') ? $fields{startpage} : 0, $fields{sorttype}, $secorder, ($fields{sh_nav} eq "on") ? "Y" : "N", ($fields{sh_dir} eq "on") ? "Y" : "N", ($fields{sh_hdr} eq "on") ? "Y" : "N", ) || print $db->errstr, ", query:[$query]<br>\\n"; $sid = $db->{\'mysql_insertid\'}; logdata($query); # delete all rights for new section $query = "delete from usersacc where sid=$sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # copy rights from parent to current section $query = "insert into usersacc (userid,sid,rights) select userid,$sid,rights from usersacc where sid=$FORM->{secparent}"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return $sid; } ###################################################################### sub update_section { # (sid, hash_fields) # изменить раздел my ($sid, %fields) = @_; my ($st, $query); $fields{secparent} = 0 if (!defined($fields{secparent})); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); return -5 if (($fields{sectype} eq \'table\') && ($fields{startpage} !~ m/^\\-*\\d+$/)); return -6 if ($fields{secorder} !~ m/^\\d+$/); $fields{sorttype} = $fields{sorttype} || \'az\'; $fields{sh_nav} = ($fields{sh_nav} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_dir} = ($fields{sh_dir} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_hdr} = ($fields{sh_hdr} =~ m/on|Y/) ? \'Y\' : \'N\'; if ($fields{sectype} eq \'table\') { $fields{plug_view} = \'\'; $fields{plug_admn} = \'\'; $fields{plug_ico} = \'\'; } elsif ($fields{sectype} eq \'asp\') { $fields{startpage} = 0; } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { if ($godaccess) { # only GODS may change fields: \'plug_view, plug_admn, plug_ico, sec_tpl\' $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, plug_view=?, plug_admn=?, plug_ico=?, sectpl=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, $fields{template}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } else { $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub move_document { # ($sid, $pid, $new_sid, $userid) # переместить документ в другой раздел my ($sid, $pid, $new_sid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($new_pid, $new_pageorder) = getonerec("select max(pid),max(pageorder) from documents where sid=$new_sid"); $new_pid++; $new_pageorder = $new_pageorder + 10; my %fields = get_document($sid, $pid); $query = "update documents set userid=?, sid=?, pid=?, pageorder=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($userid, $new_sid, $new_pid, $new_pageorder) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = "Change: <b>$sid/$pid</b> to <b>$new_sid/$new_pid</b>"; journaldata(\'move_document\', $new_sid, $new_pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub journaldata { # ($func, $sid, $pid, $userid, %fields) # записать в журнал документ/раздел/сообщение my ($func, $sid, $pid, $userid, %fields) = @_; my $query = "insert into journal (ipaddr,function,sid,pid,userid,url,pagename,pagebody,pagedate,docstatus) values (?,?,?,?,?,?,?,?,?,?)"; my $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($remoteaddr, $func, $sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; } ###################################################################### sub cutwords { # ($string, $numwords) # отрезать от новостного сообщения начало в $numwords слов my ($str, $nw) = @_; my $ret; $str =~ s!<p(.*?)>! <p$1>!i; $str =~ s!<br>! <br>!i; $str =~ s!<div(.*?)>! <div$1>!i; $str =~ s!<(/*strong)>!%%$1%%!gi; $str =~ s!<(/*)b>!%%$1strong%%!gi; $str =~ s!<img (.+?)>!%%img $1%%!i; $str =~ s/(<(?=!--)([^>]|\\n)*--(?=>)>)//ig; $str =~ s/|(<\\/?([^>]|\\n)*>)//g; $str =~ s/&nbsp;/ /g; $str =~ s/\\s+/ /g; $str =~ s!%%(/*strong)%%!<$1>!gi; $str =~ s!%%img (.+?)%%!<img $1>!i; my @a = split(/\\s/, $str); if ($#a > $nw) { $ret = join(\' \', splice(@a, 0, $nw)) . qq{<b> . . .</b>}; } else { $ret = $str; } if (($ret =~ m!<strong>!) && ($ret !~ m!</strong>!)) { $ret .= "</strong>"; } return $ret; } ###################################################################### sub round { # округлить значение my $i = shift; return $i - int($i) < 0.5 ? int($i) : int($i)+1; } ###################################################################### sub rss_expand_img_url { # разворачивает URL картинки для RSS my ($u1, $u2, $u3) = @_; return "<img $u1"."src=\\"http://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_expand_hrf_url { # разворачивает URL ссылки для RSS my ($u1, $u2, $u3) = @_; return "<a $u1"."href=\\"https://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_clear_html_to_xml { # причесывает страницу по правилам XML my $txt = shift; $txt =~ s/<img (.*?)src="(.+?)"(.*?)>/rss_expand_img_url($1,$2,$3)/ige; $txt =~ s/<a (.*?)href="(.+?)"(.*?)>/rss_expand_hrf_url($1,$2,$3)/ige; $txt =~ s/&nbsp;/ /g; $txt =~ s/\\s+/ /g; $txt =~ s/&/&amp;/g; $txt =~ s/</&lt;/gi; return $txt; } ###################################################################### sub get_root_category { # для текущего раздела (что в последнем элементе массива @treewalk) ищет предка, у которого родитель = 4 if (@treewalk) { if (@treewalk[scalar(@treewalk)-1]->[0] == 4) { return @treewalk[scalar(@treewalk)-2]->[1]; } else { return @treewalk[scalar(@treewalk)-1]->[1]; } } else { return ""; } } ###################################################################### sub send_mail_smtp { # ($host, $from, $to, $body) my ($_host, $_from, $_to, $_xbody) = @_; $_xbody = "To: $_to\\n$_xbody"; my $smtp = Net::SMTP->new($_host, Hello => \'mail.arhcity.ru\', Timeout => 30); $smtp->mail($_from); $smtp->to($_to); $smtp->data(); $smtp->datasend($_xbody); $smtp->dataend(); $smtp->quit; } ###################################################################### sub get_cookie { # возвращает значение куки по ключу (см. \\asp\\admin\\lib\\adminlib.js) my $name = shift; my $cook = $SERVER->{HTTP_COOKIE}; my @arr = split(/;\\s*/, $cook); my %ck = (); foreach my $c (@arr) { my ($k, $v) = split(/=/, $c); $ck{$k} = $v; } return $ck{$name}; } ###################################################################### sub random_str { # возвращает строку указанной длинны (или 5) из случайных символов my $len = shift || 5; my $c = \'0123456789abcdefghijklmnopqrstuvwxyz\'; my $l = length($c); my $s = \'\'; for (1 .. $len) { $s .= substr($c, int(rand()*$l), 1); } return $s; } ###################################################################### sub check_body_style { # ( body ) my $body = shift; my (@cb_arr, @ret_txt) = (); @cb_arr = (); @cb_arr = $body =~ m!<(img|a).* (src|href)="data:image/(gif|png|jpeg);base64,(\\S+)"!sg; push(@ret_txt, "&bull; Недопустимое применение ссылок формата \\"data:image\\" (".(scalar(@cb_arr)/4)." раз.)") if (@cb_arr > 0); @cb_arr = (); @cb_arr = $body =~ m/<w:LsdException/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'LsdException\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/<w:WordDocument>/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'WordDocument\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/text-indent:27\\.0pt|class="MsoNormal"|tab-stops:list -9\\.0pt|mso-layout-grid-align:/sg; push(@ret_txt, "&bull; В тексте присутствуют инлайн-стили от Microsoft Word (".scalar(@cb_arr)." раз.)") if (@cb_arr > 4); @cb_arr = (); @cb_arr = $body =~ m/style="font-family: \'Times New Roman\'/sg; push(@ret_txt, "&bull; Слишком частое использование шрифта \'Times New Roman\' (".scalar(@cb_arr)." раз.)") if (@cb_arr > 5); @cb_arr = (); @cb_arr = $body =~ m/<span style="color: .+?;">|<span style="background-color: rgb(255, 255, 255);">/sg; push(@ret_txt, "&bull; Частое/неуместное использование цветового выделения (".scalar(@cb_arr)." раз.)") if (@cb_arr > 8); if (@ret_txt) { return join("<br>\\n", @ret_txt); } else { return 0; } } ###################################################################### sub meta_og_tags { # возвращает "Open Graph" тэги для страницы my ($sid, $pid) = @_; my $pageheader = $section{secname}; $pageheader = "Городские новости" if ($sid == 0); # https://ruogp.me/ - Протокол Open Graph my $r = \'\'; $r .= qq{<meta property="og:site_name" content="Администрация города Архангельска" />\\n}; $r .= qq{<meta property="og:url" content="http://arhcity.ru/?page=$sid/$pid" />\\n}; $r .= qq{<meta property="og:title" content="$pageheader" />\\n}; $r .= qq{<meta property="og:description" content="$document{pagename}" />\\n}; $r .= qq{<meta property="og:image" content="http://arhcity.ru/pic/og-image-arhcity.jpg" />\\n}; if ($section{sectype} eq \'table\') { my $_r = \'\'; my $c = 0; my @og_image = $document{pagebody} =~ m!<img src="(.+?)" .+/>!g; foreach my $i (@og_image) { $i =~ s!http://.+?\\.ru!!g; $_r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; $c++; } if ($c > 5) { # если картинок на странице много ( >5 ) - показываем только первую my $i = @og_image[0]; $i =~ s!http://.+?\\.ru!!g; $r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; } else { $r = $_r; } } return $r; } ###################################################################### sub gen_int_EO { # (number) # возвращает случайное чётное/нечётное число в интервале 0..number в зависимости от чётности number my $n = shift; my $r = int(rand() * $n); if ($n % 2 == 0) { $r++ if ($r % 2 == 1); } else { $r++ if ($r % 2 == 0); } return $r; } ###################################################################### sub update_msie_css { # внедряем в default.css значения переменных из colors.css и создаём default-ie.css my $ret = 0; my %vars = (); my $default_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default.css"; my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; my $default_ie_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default-ie.css"; my ($t_default_css) = (stat($default_css_fn))[9]; my ($t_colors_css) = (stat($colors_css_fn))[9]; my ($t_default_ie_css) = (stat($default_ie_css_fn))[9]; if (($t_default_css > $t_default_ie_css) || ($t_colors_css > $t_default_ie_css)) { open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); open(FS, "< $default_css_fn") || die "Can\'t open $default_css_fn, $!\\n"; open(FO, "> $default_ie_css_fn") || die "Can\'t open $default_ie_css_fn, $!\\n"; while (my $l = <FS>) { next if ($l =~ m/colors.css/); $l =~ s/(var\\((--.+?)\\))/exists($vars{$2})?$vars{$2}:\'none\'/gsex; print FO $l; } close(FO); close(FS); } $ret = 1 if ((stat($default_ie_css_fn))[7] > 0); # if filesize $default_ie_css_fn > 0 - file OK. return $ret; } ###################################################################### ## XML subroutines ################################################### ###################################################################### # see http://www.arhcity.ru/1.asp # ###################################################################### sub ipcms::button { my ($args, $html) = @_; my ($ico, $spacer); if (( $args->{ico}) && ( $args->{txt})) { $spacer = \'&nbsp;\'; } if ((!$args->{ico}) && ( $args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="1" height="16">\'; } if (( $args->{ico}) && (!$args->{txt})) { $spacer = \'\'; } if ((!$args->{ico}) && (!$args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="16" height="16">\'; } if ($args->{ico}) { $ico = qq{<img src="$args->{ico}" width="16" height="16">}; } print qq{<a href="$args->{url}"><div class="shbutton">}.$ico.$spacer.$args->{txt}.qq{</div></a>}; } ###################################################################### sub ipcms::panel { my ($args, $html) = @_; my ($o_style, $style); $o_style = $args->{style} if ($args->{style}); $style = qq{ style="$o_style"} if ($o_style); print qq{<div class="border_area"$style>$html<br>}; print_dump($args); print qq{</div>\\n}; } ;; sub exit { $main::Response->End(); } ;; no lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; 1;' called at /usr/local/share/perl5/Apache/ASP/GlobalASA.pm line 122 Apache::ASP::GlobalASA::new('Apache::ASP=HASH(0x562e3465c280)') called at /usr/local/share/perl5/Apache/ASP.pm line 389 Apache::ASP::new('Apache::ASP', 'Apache2::RequestRec=SCALAR(0x562e342fd2a8)', '/var/www/HDD2/mc.arhcity.ru/asp/index.asp') called at /usr/local/share/perl5/Apache/ASP.pm line 184 Apache::ASP::handler('Apache2::RequestRec=SCALAR(0x562e342fd2a8)') called at /usr/share/perl5/Net/SMTP.pm line 15 eval {...} called at /usr/share/perl5/Net/SMTP.pm line 15 BEGIN failed--compilation aborted at /usr/share/perl5/Net/SMTP.pm line 15. at /usr/share/perl5/Net/SMTP.pm line 15. require Net/SMTP.pm called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax::BEGIN() called at /usr/share/perl5/Net/SMTP.pm line 15 eval {...} called at /usr/share/perl5/Net/SMTP.pm line 15 eval ' #line 1 /var/www/HDD2/mc.arhcity.ru/asa/global.asa package Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax; ;; use strict ;; use vars qw($Application $Session $Response $Server $Request); ;; use lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; #!/usr/bin/perl use Time::HiRes qw(gettimeofday tv_interval); use Apache::DBI; # automatic persistent database connections use DBI; use HTTP::Date; use Digest::SHA1 qw(sha1_hex sha1_base64); use Socket; use URI::UTF8::Punycode; use APR::UUID; use Text::Iconv; use Net::SMTP; # when PerlSetVar UseStrict setting on, need to declare # global variables with "use vars" ################################################################## # declare global variables use vars (\'$db\', # database interface \'$FORM\', # form data, method POST \'$QUERY\', # form data, method GET \'$POST\', # unformat form data, method POST \'$SERVER\', # server variables \'$localnet\', # access from local network \'$have_inet\', # access to internet \'$remoteaddr\', # remote IP address \'$useragent\', # UserAgent () \'$site_admin\', # Enable extra functions for site admins \'$logged_in\', # admin access by session \'$lc_logged_in\', # private cabinet access by session \'$servername\', # name of server \'$addrubrics\', # additional menu "rubrics" \'$tpl_dir\', # html template directory \'$godaccess\', # GOD access \'$hires_time\', # time generation of page ############################# \'%userinfo\', # entrie user data (hash) \'%section\', # entrie section data (hash) \'%document\', # entrie document data (hash) ############################# \'@treewalk\', # walking from leaf to root = ([$node, $secname, $sectpl]) \'%mod_params\', # parameters for plugins \'$zx_counter\', # counter for all unique repitable operations \'$site_url\', # url to site \'$site_path\', # path to site location \'$blindview\', # blind vew mode \'%CSS_vars\', # CSS variables ); ################################################################## my $host = \'localhost\'; my $db_name = \'ipcms3\'; my $dsn = "DBI:mysql:database=$db_name:host=$host"; my $username = \'root\'; my $password = \'\'; ################################################################## my $log_file; my $uploaddir; my $admin_dir = "/admin/"; my $lcab = "/lc/"; # list of datastore fields for separate \'_ex\' and non \'_ex\' fields my @doc_fields = qw(sid pid userid url pagename pagebody pagedate pagemodify pageorder sh_hdr sh_dir sh_nav sh_tab docstatus rating1 rating2); # at the begining of the page execution sub Script_OnStart { $hires_time = [gettimeofday]; $Response->Include("site_setup.asp"); # get default values for current site $log_file = "$site_path/datafiles/ipcms3.log"; $uploaddir = "$site_path/asp/data"; $Response->{\'ContentType\'} = "text/html"; $Response->{\'Charset\'} = "Windows-1251"; # $Response->{\'Expires\'} = 0; # page expired after NN seconds from download. # $Response->{\'Last-Modified:\'} = time2str(time-1); $FORM = $Request->Form(); $QUERY = $Request->QueryString(); # $POST = $Request->BinaryRead($Request->ServerVariables(\'CONTENT_LENGTH\')); # for debug $SERVER = $Request->ServerVariables(); $remoteaddr = $SERVER->{\'REMOTE_ADDR\'}; $servername = $SERVER->{\'SERVER_NAME\'}; $tpl_dir = $SERVER->{\'DOCUMENT_ROOT\'}."/templates"; $blindview = get_cookie("blindview") || 0; %userinfo = (); %section = (); %document = (); $addrubrics = \'\'; $site_admin = 0; $logged_in = 0; $godaccess = 0; $localnet = 0; $have_inet = 0; @treewalk = (); $zx_counter = 0; # Global Redirect Block... if ($servername eq \'arhcity.ru\') { $Response->Redirect("http://$site_url"); } if ($servername eq \'arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } if ($servername eq \'www.arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } # if ($SERVER->{HTTPS} ne \'on\') { # $Response->Redirect("https://www.arhcity.ru/?$SERVER->{QUERY_STRING}"); # } my $ic = Text::Iconv->new("UTF-8", "WINDOWS-1251"); my @r = (); foreach my $i (split(/\\./, $servername)) { if ($i =~ m/^xn--/) { push(@r, puny_dec($i)); } else { push(@r, $i); } } $servername = join(\'.\', @r); $servername = $ic->convert($servername); if ($SERVER->{HTTP_USER_AGENT} =~ m/edge/i) { $useragent = \'edge\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/chrome/i) { $useragent = \'chrome\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/webkit/i) { $useragent = \'safari\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/opera/i) { $useragent = \'opera\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/msie/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/trident/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/mozilla/i) { $useragent = \'mozilla\' } else { $useragent = \'unknown\'; } if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { # read CSS color variables for replace in html code (MSIE/Edge not support CSS vars); my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $CSS_vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); } if (($remoteaddr =~ m/^192\\.168\\./) || ($remoteaddr eq \'212.14.176.38\') || ($remoteaddr eq \'212.14.176.39\') || ($remoteaddr eq \'212.14.176.46\') || ($remoteaddr eq \'212.14.176.40\') || ($remoteaddr eq \'212.14.176.41\') || ($remoteaddr eq \'212.14.176.44\') || ($remoteaddr eq \'195.239.119.234\') # Городской центр гражданской защиты ) { $localnet = 1; } if (($localnet) && ( # Enable extra functions for site admins ($remoteaddr eq \'192.168.1.84\') || # GaidukAV ($remoteaddr eq \'192.168.1.44\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.45\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.46\' ) || # KorzhevDP ($remoteaddr eq \'192.168.51.144\') || # VishnyakovNS ($remoteaddr eq \'192.168.1.102\') || # EkimovKS v.1 ($remoteaddr eq \'192.168.1.110\') || # EkimovKS v.2 ($remoteaddr eq \'192.168.51.42\')) # EkimovKS v.3 ) { $site_admin = 1; } # connect to database $db = DBI->connect($dsn, $username, $password); if (! $db) { print "<p>Database server not responding.<br>Try later.</p>\\n"; $Response->End(); } # ONLY FOR RUSSIAN for MySQL !!! $db->do("set names cp1251"); if ($localnet) { # enable/disable outside scripts on site for local users without inet. ($have_inet) = getonerec("select count(ip) from squid_list where ip = \'$remoteaddr\'"); } else { $have_inet = 1; } # ------------------------------------------------------------ # $have_inet = 0; # !!! disable external scripts on site !!! # ------------------------------------------------------------ if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # !!! admin mode !!! $logged_in = 0; my $uname = $Session->{Authentication}; my $topframe = 0; if ($uname) { # logged in $logged_in = 1; $Session->{top_frame} = 0; my $adm_lib = $admin_dir . "lib/"; if ($SERVER->{\'REQUEST_URI\'} =~ m/$adm_lib/) { # read user info %userinfo = get_user_info($uname); $godaccess = 1 if ($userinfo{god} eq \'Y\'); if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no header } else { $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; } if ($SERVER->{\'REQUEST_URI\'} =~ m/(section.asp)|(page.asp)|(journal.asp)|(admin.asp)/i) { $Response->Include("page_autologoff.asp"); } } } else { # not logged in $topframe = $Session->{top_frame}; if (!$topframe) { my $location = "top.location.href=\'/admin/?t=".time()."\'"; print qq{<script>$location</script>}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n</body>\\n</html>\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with <style></style> definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "<pre>",Dumper(@_),"</pre>\\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n<script>\\n$location\\n</script".">\\n"; } ###################################################################### sub navigator { # отобразить навигатор (путь с корня до страницы) my @a = (\'<a href="/">Начало</a>\'); # if $sid in internal section (#6) - don\'t show any information my $rootsec = @treewalk[$#treewalk]; if ( (!$localnet) && ($rootsec->[0] == 6) ) { # ... } else { foreach my $i (reverse @treewalk) { push(@a, qq{<a href="/?page=$i->[0]/0">$i->[1]</a>}) if ($i->[0] > 0); } } return join(\' <span style="color:red"><img src="/pic/navar.gif" align="baseline"></span> \', @a); } ###################################################################### sub get_config_value { my $varname = shift; my ($varvalue) = getonerec("select varvalue from options where varname = \'$varname\'"); return $varvalue; } ###################################################################### sub store_config_value { my ($varname, $varvalue) = @_; my $query = "update options set varvalue=? where varname=?"; my $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($varvalue, $varname) || print $db->errstr, ", query:[$query]<br>\\n"; $st->finish; } ###################################################################### sub get_user_info { # прочитать информацию о зарегистрированном пользователе (по логину) # return hash my $user = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where username = \'$user\'"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub get_user_id_info { # прочитать информацию о зарегистрированном пользователе (по id) # return hash my $user_id = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where id = $user_id"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub make_pw_hash { # (password) # Создание уникального хэша по паролю my $password = shift; my $letts = \'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\'; my $lettl = length($letts); my $salt = \'\'; $password = substr($password, 0, 32) if (length($password) > 32); # limit password length for my $i (1 .. 5) { $salt .= substr($letts, int(rand() * $lettl), 1); } return $salt.sha1_base64($salt.$password); } ###################################################################### sub check_pw_hash { # (password, pwd_hash) # проверка на соответствие хэша и пароля my $password = shift; my $pw_hash = shift; my $salt = substr($pw_hash, 0, 5); $password = substr($password, 0, 32) if (length($password) > 32); # limit password length return (substr($pw_hash, 5) eq sha1_base64($salt.$password)); } ###################################################################### sub check_auth { # (user, password) # проверка авторизации my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'N\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub check_auth_lc { # (user, password) # проверка авторизации lcab my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'Y\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub get_inherit_tpl { # (sid) # найти имя наследуемого шаблона дизайна my $tpn = "default"; my $tpn2 = \'\'; @treewalk = tree_walk(shift); foreach my $i (reverse(@treewalk)) { if ($i->[2] ne \'\') { $tpn2 = $tpn; $tpn = $i->[2]; } } return ($tpn, $tpn2); } ###################################################################### sub get_tpl_list { # пполучить список доступных шаблонов дизайна my ($c, @ret) = 0; opendir(D, $tpl_dir); while (my $d = readdir(D)) { if ($d =~ m/^(.+)\\.asp$/) { push(@ret, $1); } } closedir(D); return sort @ret; } ###################################################################### sub tree_walk { # ($sid) # пройтись по дереву от указанного раздела до корня, записать в массив ($node, $secname, $sectpl) my ($node, $pnode, $secname, $sectpl, @tw) = shift; my $c = 0; while ($node != 0) { ($node, $pnode, $secname, $sectpl) = getonerec("select sid,secparent,secname,sectpl from section where sid=$node"); push(@tw, ([$node, $secname, $sectpl])); $node = $pnode; $c++; if ($c > 20) { # если очень большое количество итераций - значит в базе ошибка. my $t = \'\'; foreach (@tw) { $t .= \' \'.$_->[0]; } print error("В базе данных ошибка! Возможно зацикленная рекурсия. Срочно обратитесь к администратору.<br>tree_walk: [$t]"); last; } } return @tw; } ###################################################################### sub getonerec { # (query) # прочитать одну запись из базы my ($query, $st, @row) = shift; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]<br>\\n"; $st->execute() || print $db->errstr, ", Q:[$query]<br>\\n"; @row = $st->fetchrow_array; $st->finish; return @row; } ###################################################################### sub get_sql_list { # прочитать список из базы # return @arr = (\'a1\',\'b1\',\'c1\'); my $q = shift; my ($s,@r,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { push(@ret, $r[0]); } $s->finish; return @ret; } ###################################################################### sub get_sql_arr { # прочитать список списков (таблицу) из базы # return @arr = ( [\'a1\',\'a2\'], [\'b1\',\'b2\'], [\'c1\',\'c2\'] ); my $q = shift; my ($s,$rf,@r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { @rt = (); for my $i (0 .. scalar(@r)-1) { $rt[0][$i] = $r[$i]; } push(@ret, @rt); } $s->finish; return @ret; } ###################################################################### sub get_sql_arhash { # (query) # прочитать список хэшей (таблицу с именованными столбцами) из базы # return array of hashes my $q = shift; my ($s,$rf,$r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { push(@ret, $r); } $s->finish; return @ret; } ###################################################################### sub input_text { # ($name, $style, $value) # создать текстовое поле ввода my ($name, $style, $value) = @_; $style .= qq{ id="id$name"} if ($name); my $ret = qq{<input type="text" name="$name" value="$value" $style>}; return $ret; } ###################################################################### sub input_checkbox_1Y { # ($name, $style, $value, $label) # создать поле ввода чекбокс (одиночный) my ($name, $style, $value, $label) = @_; my $ret = ""; my $checked = (($value eq "Y") || ($value eq "on")) ? "checked" : ""; $zx_counter++; $ret = qq{<input type="checkbox" name="$name" id="id$zx_counter$name" $checked $style>&nbsp;<label for="id$zx_counter$name">$label</label>}; return $ret; } ###################################################################### sub input_radio { # ($name, $style, $js, $br, $checked, %values) # создать поле ввода радиоботтон (группу) my ($name, $style, $js, $br, $checked, %values) = @_; my $ret; my $j = ""; foreach my $i (sort keys %values) { if ($js ne \'\') { $j = qq{onclick="$js(\'$i\');"}; } my $checkstr = ($checked eq $i) ? "checked" : ""; $ret .= qq{<input type="radio" name="$name" id="$i" value="$i" $checkstr $style $j>\\n<label for="$i">$values{$i}</label>$br\\n}; } return $ret; } ###################################################################### sub input_textarea { # ($name, $style, $value) # создать поле тексареа my ($name, $style, $value) = @_; my $ret = qq{<textarea name="$name" $style>$value</textarea>}; return $ret; } ###################################################################### sub input_texteditor { # ($name, $imgdir, $value) # создать текстовый редактор на базе FCKeditor my ($name, $imgdir, $value) = @_; my $te = $Response->TrapInclude("page_fckeditor.asp", $name, $imgdir, $value); return $$te; } ###################################################################### sub input_list_arr { # ($name, $style, $currvalue, @arr) # создать поле список из 2d массива, с отключением отображения id # @arr = ( [1,\'a1\'], [2,\'a2\'], [3,\'a3\'] ); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); my $nonum = 0; my $size = qq{size="1"}; $size = $1 if ($style =~ s/(size=["\']*\\d+["\']*)//i); $nonum = 1 if ($style =~ s/nonum//i); $style .= qq{ id="id$name"} if ($name); $ret = qq{<select name="$name" $size $style>\\n}; for my $i (0 .. scalar(@arr)-1) { $sel = \'\'; if ($currvalue =~ m/^\\d+$/) { $sel = "selected" if ($arr[$i][0] == $currvalue); } else { $sel = "selected" if ($arr[$i][0] eq $currvalue); } if ($nonum) { $ret .= qq{<option $sel value="$arr[$i][0]">$arr[$i][1]</option>\\n}; } else { $ret .= qq{<option $sel value="$arr[$i][0]">[$arr[$i][0]] $arr[$i][1]</option>\\n}; } } $ret .= "</select>"; return $ret; } ###################################################################### sub input_list_arr_X1 { # ($name, $style, $currvalue, @arr) # создать поле список из 1d массива # @arr = (\'a1\',\'a2\',\'a3\'); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); $style .= qq{ id="id$name"} if ($name); $ret = "<select name=\\"$name\\" size=\\"1\\" $style>\\n"; foreach my $i (@arr) { if ($i eq $currvalue) { $sel = "selected"; } else { $sel = ""; } $ret .= qq{<option $sel value="$i">$i</option>\\n}; } $ret .= "</select>"; return $ret; } ###################################################################### sub check_acc { # ($sid, $acc_letters) # проверка прав доступа к разделу my ($sid, $acs) = @_; return 1 if ($godaccess); if ($sid =~ m/^\\d+$/) { #my @rghts = get_sql_list("select rights from usersacc where userid=$userinfo{id} and sid=$sid"); my $query = "select usersacc.rights from users inner join usersacc on (users.id = usersacc.userid) where users.enable = \'Y\' and users.id = $userinfo{id} and usersacc.sid = $sid"; my @rghts = get_sql_list($query); my $rights = join(\'\', @rghts); foreach my $ac (split(\'\', $acs)) { return 1 if ($rights =~ m/$ac/); } return 0; } return 0; } ###################################################################### sub tablist { # $sid, $pid, \'tabsheet\', \'focus\', startN, (array of names) # создание панели с закладками (используется в page.asp и section.asp) my ($sid, $pid, $tabsheet_name, $focus_name, $start_page, @pages) = @_; my $pagenum = scalar(@pages)-1; my ($out,$focus1,$focus2); =pod =head1 Параметры вызова: tablist($sid, $pid, \'tabsheet\', \'focus\', startN, (array of names)); =item $sid, $pid Номера раздела и страницы Если номер раздела < 0 - закладка со ссылкой на дерево объектов НЕ отображается. =item \'tabsheet\' HTML Идентификатор панели с табами =item startN Номер закладки, которую нужно открыть при старте страницы Для этого в запросе должен присутствовать параметр "ctsh=N" где N - номер закладки =item \'focus\' Идентификатор HTML объекта для установки фокуса при открытии каждой из закладок =item (array of names) Список строк, являющихся текстом на закладках =head1 Пример реализации панели с табами: <style> #tabsheet0 {display:none} /* в некоторых версяиях браузеров из за ошибки надо комментировать эту строку */ #tabsheet1 {display:none} #tabsheet2 {display:none} .tabsheet { ... } </style> <#% my @tabs = ( \'<img src="/pic/page1.png"> Page One\', \'<img src="/pic/page2.png"> Page Two\', \'<img src="/pic/page3.png"> Page Three\' ); my $ctsh; $ctsh = $FORM->{ctsh}; $ctsh = $QUERY->{ctsh} if ($ctsh eq \'\'); print tablist(-1, \'\', \'tabsheet\', \'fcs\', ($ctsh =~ m/[012]/)?$ctsh:0, @tabs); %#> <div class="tabarea"> <table border="0" width="100%" cellpadding="8" cellspacing="0"><tr><td> <div id="tabsheet0" class="tabsheet">Page 1<br><input type="text" id="fcs0"></div> <div id="tabsheet1" class="tabsheet">Page 2<br><input type="text" id="fcs1"></div> <div id="tabsheet2" class="tabsheet">Page 3<br><input type="text" id="fcs2"></div> </td></tr></table> </div> =cut my $css = qq[ <style> #tablist { padding: 3px 0 3px 6px; margin-left: 0; font: 13px Tahoma; /* line-height: 16px; */ white-space: nowrap; } #tablist li { list-style: none; margin: 0; display: inline; white-space: nowrap; } #tablist li a { color: #555; padding: 3px 6px; margin-left: 3px; border: 1px solid #888; border-bottom: none; background: #ddd; text-decoration: none; font-weight: normal; border-top-left-radius: 6px; border-top-right-radius: 6px; } </style> ]; my $javascript = qq[ <script language="JavaScript"> window.onload = function(){ showTab($start_page); } function showTab(tabnum) { for (i = 0; i <= $pagenum; i++) { document.getElementById(\'$tabsheet_name\'+i).style.display = \'none\'; tln = document.getElementById(\'xtl\'+i); tln.style.color = \'#555\'; tln.style.background = \'#ddd\'; tln.style.borderBottom = \'1px solid #888\'; } var tsheet = document.getElementById(\'$tabsheet_name\'+tabnum); var fcname = document.getElementById(\'$focus_name\'+tabnum); var tln = document.getElementById(\'xtl\'+tabnum); if (tsheet) { tsheet.style.display = \'block\'; } if (fcname) { fcname.focus(); } if (tln) { tln.style.color = \'#000\'; tln.style.background = \'white\'; tln.style.borderBottom = \'1px solid white\'; tln.style.backgroundImage = \'url(/admin/pic/tab_bg.gif)\'; } } </script]; # See ...Perl\\site\\lib\\Apache\\ASP\\GlobalASA.pm, lines 91,92... $out .= $css.$javascript.">\\n"; # stupid bug... $out .= qq{\\n<ul id="tablist" style="margin-bottom:0px;">\\n}; if ($sid > 0) { # отображение закладки со ссылкой на дерево объектов $out .= qq{ <li><a href="treejx.asp?sid=$sid&pid=$pid" style="padding-left:0;margin-left:0;background-color:#20a020;color:#c0ffc0;text-decoration:none" target="treeframe">&nbsp;<acronym title="Отобразить курсор на дереве объектов"><img src="/admin/pic/tree/node-tree.png" class="trico">&nbsp;$sid/$pid&nbsp;</acronym></a></li>\\n}; } for(my $i=0; $i<=$pagenum; $i++) { $pages[0] = qq{<span style="color:blue">$pages[0]</span>} if (($section{sectype} eq \'asp\') || ($sid == 0)); $out .= qq{ <li><a href="#$i" id="xtl$i" onclick="showTab($i)">$pages[$i]</a></li>\\n}; } $out .= qq{</ul>\\n}; return $out; } ####################################################################### sub get_indexgroup_str { # (index_name) # получить строку списка разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return $idx; } ####################################################################### sub get_indexgroup_lst { # (index_name) # получить список разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return split(/,\\s*/, $idx); } ####################################################################### sub exist_in_indexgroup { # ($index_name, $value) # проверить наличие $value в списке разделов по имени my ($index_name, $value) = @_; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return exist_in_list($value, split(/,\\s*/, $idx)); } ###################################################################### sub recalctree { # ($sid) # получить список всех подчиненных разделов от указанного my $sl = shift; $sl =~ s/\\D+/,/g; my @srvindex = (); my ($q, $s, $r); $q = "select sid from section order by sid"; $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { my @tw = (); @treewalk = &tree_walk($r->{sid}); foreach my $item (reverse @treewalk) { push(@tw, $item->[0]); } my %union = (); my %isect = (); # объединение и пересечение множеств @tw и "$sl", результат в %union и %isect foreach my $e (@tw, split(\',\', $sl)) { $union{$e}++ && $isect{$e}++ } push(@srvindex, $r->{sid}) if (scalar(keys %isect)); } $s->finish; return @srvindex; } ####################################################################### sub autorecalctree { # Обновление индексных групп при изменении иерархии разделов my $visual = shift; my ($q1, $s1, $r1); my ($q2, $s2, $r2); print qq{<div id="autoupdate" style="padding-top:10px;">Обновление индексных групп : } if ($visual); $q1 = "select id,slist from srvindex order by id desc"; $s1 = $db->prepare($q1) || print $db->errstr, ", query:[$q1]<br>\\n"; $s1->execute() || print $db->errstr, ", query:[$q1]<br>\\n"; while ( $r1 = $s1->fetchrow_hashref ) { print qq{<span style="background-color:blue;color:white">&nbsp;$r1->{id}&nbsp;</span>&nbsp;} if ($visual); $Response->Flush() if ($visual); # anti timeout solution my $flist = join(\',\', recalctree($r1->{slist})); $q2 = "update srvindex set flist=? where id=$r1->{id}"; $s2 = $db->prepare($q2) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->execute($flist) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->finish; } $s1->finish; print qq{\\n</div>\\n<style>#autoupdate {display:none} </style>\\n} if ($visual); } ####################################################################### sub check_for_secdel { # (sid) # проверка возможности удаления раздела my ($sid) = @_; my @cd_msg = (); my ($cs, $cp, $cf) = (0, 0, 0); my $filedir = "$uploaddir/$sid"; # считаем количество подразделов ($cs) = getonerec("select count(sid) from section where secparent = $sid"); push(@cd_msg, "Разделов: <span style=\'color:red\'>$cs</span>") if ($cs); # считаем количество документов в разделе ($cp) = getonerec("select count(pid) from documents where sid = $sid"); push(@cd_msg, "Страниц: <span style=\'color:red\'>$cp</span>") if ($cp); # считаем количество файлов в разделе if (opendir(D, $filedir)) { my @rm_dir = readdir(D); closedir(D); $cf = scalar(@rm_dir); # уменьшаем $cf из за служебных папок: \'.\' и \'..\' foreach my $d (@rm_dir) { $cf-- if ($d =~ m/^\\.+$/); } } push(@cd_msg, "Файлов: <span style=\'color:red\'>$cf</span>") if ($cf); return @cd_msg; } ###################################################################### sub get_section { # (sid) # прочитать информацию о разделе # return hash my ($sid) = @_; my (%ret, $query, $st, $row) = (); if ($sid > 0) { $query = "select * from section where sid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; } return %ret; } ###################################################################### sub get_document { # (sid, pid) # прочитать документ # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); $query = "select * from documents where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; $st->finish; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } return %ret; } ###################################################################### sub get_document_ex { # (sid, pid) # прочитать документ с расширенными полями # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); %ret = get_document($sid, $pid); $query = "select field,value from documents_ex where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { $ret{$row->{field}} = $row->{value}; } $st->finish; return %ret; } ###################################################################### sub get_sec_documents { # (sid, \'body\') # прочитать все документы раздела (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body) = @_; my (@ret, $query, $st, $row, $b) = (); $b = \'pagebody,\' if ($body); my $fields = "sid,pid,userid,url,pagename,".$b."pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus"; $query = "select $fields from documents where sid=? order by pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; return @ret; } ###################################################################### sub get_sec_documents_ex { # (sid, body, x_where) # прочитать все документы раздела с расширенными полями (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body, $x_where) = @_; my (@ret, @ret_ex, $query, $st, $row, $b) = (); $b = \'documents.pagebody,\' if ($body); my $fields = " documents.sid, documents.pid, documents.userid, documents.url, documents.pagename, $b documents.pagedate, documents.pagemodify, documents.pageorder, documents.sh_hdr, documents.sh_dir, documents.sh_nav, documents.sh_tab, documents.docstatus, documents_ex.field, documents_ex.value"; $query = "select $fields from documents left outer join documents_ex on (documents_ex.sid = documents.sid) and (documents_ex.pid = documents.pid) where documents.sid = $sid"; $query = "$query and ($x_where)" if ($x_where); # open(F, ">>$site_path/asa/q.log"); # print F "get_sec_documents_ex: $query\\n\\n"; # close(F); $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute() || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; # получили массив @ret с дублями строк для полей из documents my %h = (); foreach my $i (@ret) { # чтобы избавится от дублей пихаем строки в хэш, где ключ = \'sid.pid\' if (!defined($h{"$i->{sid}.$i->{pid}"})) { $h{"$i->{sid}.$i->{pid}"} = { \'sid\' => $i->{\'sid\'}, \'pid\' => $i->{\'pid\'}, \'userid\' => $i->{\'userid\'}, \'url\' => $i->{\'url\'}, \'pagename\' => $i->{\'pagename\'}, \'pagedate\' => $i->{\'pagedate\'}, \'pagemodify\' => $i->{\'pagemodify\'}, \'pageorder\' => $i->{\'pageorder\'}, \'sh_hdr\' => $i->{\'sh_hdr\'}, \'sh_dir\' => $i->{\'sh_dir\'}, \'sh_nav\' => $i->{\'sh_nav\'}, \'sh_tab\' => $i->{\'sh_tab\'}, \'docstatus\' => $i->{\'docstatus\'}, $i->{\'field\'} => $i->{\'value\'}, }; } else { # в случае сущесвования такой же строки в хэше - добавляем очередное поле из documents_ex $h{"$i->{sid}.$i->{pid}"}->{$i->{\'field\'}} = $i->{\'value\'}; } } @ret = (); # перекидываем всё из хэша в массив foreach my $i (keys %h) { push(@ret, $h{$i}); } return @ret; } ###################################################################### sub create_document { # (sid, userid, hash_fields) # создать документ в указанном разделе my ($sid, $userid, %fields) = @_; my ($pid, $query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # search new $pid for $sid my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $pid++; # set default values for new document $fields{pageorder} = $pid * 10; # insert new fields of document $query = "insert into documents (sid,pid,userid,url,pagename,pagebody,pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'create_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_document_ex { # (sid, userid, hash_fields) # создать документ с расширенными полями в указанном разделе my ($sid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { create_document($sid, $userid, %fields); my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $fields{pagebody} = \'\'; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'create_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document { # ($sid, $pid, $userid) # удалить документ my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document_ex { # ($sid, $pid, $userid) # удалить документ с расширенными полями my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); my %fields_ex = get_document_ex($sid, $pid); $query = "delete from documents_ex where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = \'\'; foreach my $i (keys %fields_ex) { $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'delete_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_section { # (sid) # удалить раздел my ($sid) = @_; my ($st, $query); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { $query = "delete from section where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); # remove rights for deleted section $query = "delete from usersacc where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document { # (sid, pid, userid, hash_fields) # заменить документ my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # update fields of document $query = "update documents set userid=?,url=?,pagename=?,pagebody=?,pagedate=?,pagemodify=?,pageorder=?,sh_hdr=?,sh_dir=?,sh_nav=?,sh_tab=?,docstatus=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'replace_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document_ex { # (sid, pid, userid, hash_fields) # заменить документ с расширенными полями my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { replace_document($sid, $pid, $userid, %fields); $fields{pagebody} = \'\'; # delete \'_ex\' fields in documents_ex $query = "delete from documents_ex where sid = $sid and pid = $pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]== $fields_ex{$i}\\n"; } journaldata(\'replace_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_section { # (hash_fields) # создать раздел my (%fields) = @_; my ($st, $sid, $query); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($secorder) = getonerec("select max(secorder) from section where secparent=$FORM->{secparent}"); $secorder = $secorder + 10; $fields{sectype} = $fields{sectype} || \'table\'; $fields{sorttype} = $fields{sorttype} || \'az\'; # insert record of section $query = "insert into section (secparent,secname,secdescr,sectype,plug_view,plug_admn,plug_ico,startpage,sorttype,secorder,sh_nav,sh_dir,sh_hdr) values (?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secparent}, $fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, ($fields{sectype} eq \'table\') ? $fields{startpage} : 0, $fields{sorttype}, $secorder, ($fields{sh_nav} eq "on") ? "Y" : "N", ($fields{sh_dir} eq "on") ? "Y" : "N", ($fields{sh_hdr} eq "on") ? "Y" : "N", ) || print $db->errstr, ", query:[$query]<br>\\n"; $sid = $db->{\'mysql_insertid\'}; logdata($query); # delete all rights for new section $query = "delete from usersacc where sid=$sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # copy rights from parent to current section $query = "insert into usersacc (userid,sid,rights) select userid,$sid,rights from usersacc where sid=$FORM->{secparent}"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return $sid; } ###################################################################### sub update_section { # (sid, hash_fields) # изменить раздел my ($sid, %fields) = @_; my ($st, $query); $fields{secparent} = 0 if (!defined($fields{secparent})); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); return -5 if (($fields{sectype} eq \'table\') && ($fields{startpage} !~ m/^\\-*\\d+$/)); return -6 if ($fields{secorder} !~ m/^\\d+$/); $fields{sorttype} = $fields{sorttype} || \'az\'; $fields{sh_nav} = ($fields{sh_nav} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_dir} = ($fields{sh_dir} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_hdr} = ($fields{sh_hdr} =~ m/on|Y/) ? \'Y\' : \'N\'; if ($fields{sectype} eq \'table\') { $fields{plug_view} = \'\'; $fields{plug_admn} = \'\'; $fields{plug_ico} = \'\'; } elsif ($fields{sectype} eq \'asp\') { $fields{startpage} = 0; } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { if ($godaccess) { # only GODS may change fields: \'plug_view, plug_admn, plug_ico, sec_tpl\' $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, plug_view=?, plug_admn=?, plug_ico=?, sectpl=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, $fields{template}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } else { $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub move_document { # ($sid, $pid, $new_sid, $userid) # переместить документ в другой раздел my ($sid, $pid, $new_sid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($new_pid, $new_pageorder) = getonerec("select max(pid),max(pageorder) from documents where sid=$new_sid"); $new_pid++; $new_pageorder = $new_pageorder + 10; my %fields = get_document($sid, $pid); $query = "update documents set userid=?, sid=?, pid=?, pageorder=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($userid, $new_sid, $new_pid, $new_pageorder) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = "Change: <b>$sid/$pid</b> to <b>$new_sid/$new_pid</b>"; journaldata(\'move_document\', $new_sid, $new_pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub journaldata { # ($func, $sid, $pid, $userid, %fields) # записать в журнал документ/раздел/сообщение my ($func, $sid, $pid, $userid, %fields) = @_; my $query = "insert into journal (ipaddr,function,sid,pid,userid,url,pagename,pagebody,pagedate,docstatus) values (?,?,?,?,?,?,?,?,?,?)"; my $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($remoteaddr, $func, $sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; } ###################################################################### sub cutwords { # ($string, $numwords) # отрезать от новостного сообщения начало в $numwords слов my ($str, $nw) = @_; my $ret; $str =~ s!<p(.*?)>! <p$1>!i; $str =~ s!<br>! <br>!i; $str =~ s!<div(.*?)>! <div$1>!i; $str =~ s!<(/*strong)>!%%$1%%!gi; $str =~ s!<(/*)b>!%%$1strong%%!gi; $str =~ s!<img (.+?)>!%%img $1%%!i; $str =~ s/(<(?=!--)([^>]|\\n)*--(?=>)>)//ig; $str =~ s/|(<\\/?([^>]|\\n)*>)//g; $str =~ s/&nbsp;/ /g; $str =~ s/\\s+/ /g; $str =~ s!%%(/*strong)%%!<$1>!gi; $str =~ s!%%img (.+?)%%!<img $1>!i; my @a = split(/\\s/, $str); if ($#a > $nw) { $ret = join(\' \', splice(@a, 0, $nw)) . qq{<b> . . .</b>}; } else { $ret = $str; } if (($ret =~ m!<strong>!) && ($ret !~ m!</strong>!)) { $ret .= "</strong>"; } return $ret; } ###################################################################### sub round { # округлить значение my $i = shift; return $i - int($i) < 0.5 ? int($i) : int($i)+1; } ###################################################################### sub rss_expand_img_url { # разворачивает URL картинки для RSS my ($u1, $u2, $u3) = @_; return "<img $u1"."src=\\"http://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_expand_hrf_url { # разворачивает URL ссылки для RSS my ($u1, $u2, $u3) = @_; return "<a $u1"."href=\\"https://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_clear_html_to_xml { # причесывает страницу по правилам XML my $txt = shift; $txt =~ s/<img (.*?)src="(.+?)"(.*?)>/rss_expand_img_url($1,$2,$3)/ige; $txt =~ s/<a (.*?)href="(.+?)"(.*?)>/rss_expand_hrf_url($1,$2,$3)/ige; $txt =~ s/&nbsp;/ /g; $txt =~ s/\\s+/ /g; $txt =~ s/&/&amp;/g; $txt =~ s/</&lt;/gi; return $txt; } ###################################################################### sub get_root_category { # для текущего раздела (что в последнем элементе массива @treewalk) ищет предка, у которого родитель = 4 if (@treewalk) { if (@treewalk[scalar(@treewalk)-1]->[0] == 4) { return @treewalk[scalar(@treewalk)-2]->[1]; } else { return @treewalk[scalar(@treewalk)-1]->[1]; } } else { return ""; } } ###################################################################### sub send_mail_smtp { # ($host, $from, $to, $body) my ($_host, $_from, $_to, $_xbody) = @_; $_xbody = "To: $_to\\n$_xbody"; my $smtp = Net::SMTP->new($_host, Hello => \'mail.arhcity.ru\', Timeout => 30); $smtp->mail($_from); $smtp->to($_to); $smtp->data(); $smtp->datasend($_xbody); $smtp->dataend(); $smtp->quit; } ###################################################################### sub get_cookie { # возвращает значение куки по ключу (см. \\asp\\admin\\lib\\adminlib.js) my $name = shift; my $cook = $SERVER->{HTTP_COOKIE}; my @arr = split(/;\\s*/, $cook); my %ck = (); foreach my $c (@arr) { my ($k, $v) = split(/=/, $c); $ck{$k} = $v; } return $ck{$name}; } ###################################################################### sub random_str { # возвращает строку указанной длинны (или 5) из случайных символов my $len = shift || 5; my $c = \'0123456789abcdefghijklmnopqrstuvwxyz\'; my $l = length($c); my $s = \'\'; for (1 .. $len) { $s .= substr($c, int(rand()*$l), 1); } return $s; } ###################################################################### sub check_body_style { # ( body ) my $body = shift; my (@cb_arr, @ret_txt) = (); @cb_arr = (); @cb_arr = $body =~ m!<(img|a).* (src|href)="data:image/(gif|png|jpeg);base64,(\\S+)"!sg; push(@ret_txt, "&bull; Недопустимое применение ссылок формата \\"data:image\\" (".(scalar(@cb_arr)/4)." раз.)") if (@cb_arr > 0); @cb_arr = (); @cb_arr = $body =~ m/<w:LsdException/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'LsdException\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/<w:WordDocument>/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'WordDocument\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/text-indent:27\\.0pt|class="MsoNormal"|tab-stops:list -9\\.0pt|mso-layout-grid-align:/sg; push(@ret_txt, "&bull; В тексте присутствуют инлайн-стили от Microsoft Word (".scalar(@cb_arr)." раз.)") if (@cb_arr > 4); @cb_arr = (); @cb_arr = $body =~ m/style="font-family: \'Times New Roman\'/sg; push(@ret_txt, "&bull; Слишком частое использование шрифта \'Times New Roman\' (".scalar(@cb_arr)." раз.)") if (@cb_arr > 5); @cb_arr = (); @cb_arr = $body =~ m/<span style="color: .+?;">|<span style="background-color: rgb(255, 255, 255);">/sg; push(@ret_txt, "&bull; Частое/неуместное использование цветового выделения (".scalar(@cb_arr)." раз.)") if (@cb_arr > 8); if (@ret_txt) { return join("<br>\\n", @ret_txt); } else { return 0; } } ###################################################################### sub meta_og_tags { # возвращает "Open Graph" тэги для страницы my ($sid, $pid) = @_; my $pageheader = $section{secname}; $pageheader = "Городские новости" if ($sid == 0); # https://ruogp.me/ - Протокол Open Graph my $r = \'\'; $r .= qq{<meta property="og:site_name" content="Администрация города Архангельска" />\\n}; $r .= qq{<meta property="og:url" content="http://arhcity.ru/?page=$sid/$pid" />\\n}; $r .= qq{<meta property="og:title" content="$pageheader" />\\n}; $r .= qq{<meta property="og:description" content="$document{pagename}" />\\n}; $r .= qq{<meta property="og:image" content="http://arhcity.ru/pic/og-image-arhcity.jpg" />\\n}; if ($section{sectype} eq \'table\') { my $_r = \'\'; my $c = 0; my @og_image = $document{pagebody} =~ m!<img src="(.+?)" .+/>!g; foreach my $i (@og_image) { $i =~ s!http://.+?\\.ru!!g; $_r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; $c++; } if ($c > 5) { # если картинок на странице много ( >5 ) - показываем только первую my $i = @og_image[0]; $i =~ s!http://.+?\\.ru!!g; $r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; } else { $r = $_r; } } return $r; } ###################################################################### sub gen_int_EO { # (number) # возвращает случайное чётное/нечётное число в интервале 0..number в зависимости от чётности number my $n = shift; my $r = int(rand() * $n); if ($n % 2 == 0) { $r++ if ($r % 2 == 1); } else { $r++ if ($r % 2 == 0); } return $r; } ###################################################################### sub update_msie_css { # внедряем в default.css значения переменных из colors.css и создаём default-ie.css my $ret = 0; my %vars = (); my $default_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default.css"; my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; my $default_ie_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default-ie.css"; my ($t_default_css) = (stat($default_css_fn))[9]; my ($t_colors_css) = (stat($colors_css_fn))[9]; my ($t_default_ie_css) = (stat($default_ie_css_fn))[9]; if (($t_default_css > $t_default_ie_css) || ($t_colors_css > $t_default_ie_css)) { open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); open(FS, "< $default_css_fn") || die "Can\'t open $default_css_fn, $!\\n"; open(FO, "> $default_ie_css_fn") || die "Can\'t open $default_ie_css_fn, $!\\n"; while (my $l = <FS>) { next if ($l =~ m/colors.css/); $l =~ s/(var\\((--.+?)\\))/exists($vars{$2})?$vars{$2}:\'none\'/gsex; print FO $l; } close(FO); close(FS); } $ret = 1 if ((stat($default_ie_css_fn))[7] > 0); # if filesize $default_ie_css_fn > 0 - file OK. return $ret; } ###################################################################### ## XML subroutines ################################################### ###################################################################### # see http://www.arhcity.ru/1.asp # ###################################################################### sub ipcms::button { my ($args, $html) = @_; my ($ico, $spacer); if (( $args->{ico}) && ( $args->{txt})) { $spacer = \'&nbsp;\'; } if ((!$args->{ico}) && ( $args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="1" height="16">\'; } if (( $args->{ico}) && (!$args->{txt})) { $spacer = \'\'; } if ((!$args->{ico}) && (!$args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="16" height="16">\'; } if ($args->{ico}) { $ico = qq{<img src="$args->{ico}" width="16" height="16">}; } print qq{<a href="$args->{url}"><div class="shbutton">}.$ico.$spacer.$args->{txt}.qq{</div></a>}; } ###################################################################### sub ipcms::panel { my ($args, $html) = @_; my ($o_style, $style); $o_style = $args->{style} if ($args->{style}); $style = qq{ style="$o_style"} if ($o_style); print qq{<div class="border_area"$style>$html<br>}; print_dump($args); print qq{</div>\\n}; } ;; sub exit { $main::Response->End(); } ;; no lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; 1;' called at /usr/local/share/perl5/Apache/ASP/GlobalASA.pm line 122 Apache::ASP::GlobalASA::new('Apache::ASP=HASH(0x562e3465c280)') called at /usr/local/share/perl5/Apache/ASP.pm line 389 Apache::ASP::new('Apache::ASP', 'Apache2::RequestRec=SCALAR(0x562e342fd2a8)', '/var/www/HDD2/mc.arhcity.ru/asp/index.asp') called at /usr/local/share/perl5/Apache/ASP.pm line 184 Apache::ASP::handler('Apache2::RequestRec=SCALAR(0x562e342fd2a8)') called at /usr/share/perl5/Net/SMTP.pm line 15 eval {...} called at /usr/share/perl5/Net/SMTP.pm line 15 Compilation failed in require at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12. at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12. Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax::BEGIN() called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 eval {...} called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 eval ' #line 1 /var/www/HDD2/mc.arhcity.ru/asa/global.asa package Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax; ;; use strict ;; use vars qw($Application $Session $Response $Server $Request); ;; use lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; #!/usr/bin/perl use Time::HiRes qw(gettimeofday tv_interval); use Apache::DBI; # automatic persistent database connections use DBI; use HTTP::Date; use Digest::SHA1 qw(sha1_hex sha1_base64); use Socket; use URI::UTF8::Punycode; use APR::UUID; use Text::Iconv; use Net::SMTP; # when PerlSetVar UseStrict setting on, need to declare # global variables with "use vars" ################################################################## # declare global variables use vars (\'$db\', # database interface \'$FORM\', # form data, method POST \'$QUERY\', # form data, method GET \'$POST\', # unformat form data, method POST \'$SERVER\', # server variables \'$localnet\', # access from local network \'$have_inet\', # access to internet \'$remoteaddr\', # remote IP address \'$useragent\', # UserAgent () \'$site_admin\', # Enable extra functions for site admins \'$logged_in\', # admin access by session \'$lc_logged_in\', # private cabinet access by session \'$servername\', # name of server \'$addrubrics\', # additional menu "rubrics" \'$tpl_dir\', # html template directory \'$godaccess\', # GOD access \'$hires_time\', # time generation of page ############################# \'%userinfo\', # entrie user data (hash) \'%section\', # entrie section data (hash) \'%document\', # entrie document data (hash) ############################# \'@treewalk\', # walking from leaf to root = ([$node, $secname, $sectpl]) \'%mod_params\', # parameters for plugins \'$zx_counter\', # counter for all unique repitable operations \'$site_url\', # url to site \'$site_path\', # path to site location \'$blindview\', # blind vew mode \'%CSS_vars\', # CSS variables ); ################################################################## my $host = \'localhost\'; my $db_name = \'ipcms3\'; my $dsn = "DBI:mysql:database=$db_name:host=$host"; my $username = \'root\'; my $password = \'\'; ################################################################## my $log_file; my $uploaddir; my $admin_dir = "/admin/"; my $lcab = "/lc/"; # list of datastore fields for separate \'_ex\' and non \'_ex\' fields my @doc_fields = qw(sid pid userid url pagename pagebody pagedate pagemodify pageorder sh_hdr sh_dir sh_nav sh_tab docstatus rating1 rating2); # at the begining of the page execution sub Script_OnStart { $hires_time = [gettimeofday]; $Response->Include("site_setup.asp"); # get default values for current site $log_file = "$site_path/datafiles/ipcms3.log"; $uploaddir = "$site_path/asp/data"; $Response->{\'ContentType\'} = "text/html"; $Response->{\'Charset\'} = "Windows-1251"; # $Response->{\'Expires\'} = 0; # page expired after NN seconds from download. # $Response->{\'Last-Modified:\'} = time2str(time-1); $FORM = $Request->Form(); $QUERY = $Request->QueryString(); # $POST = $Request->BinaryRead($Request->ServerVariables(\'CONTENT_LENGTH\')); # for debug $SERVER = $Request->ServerVariables(); $remoteaddr = $SERVER->{\'REMOTE_ADDR\'}; $servername = $SERVER->{\'SERVER_NAME\'}; $tpl_dir = $SERVER->{\'DOCUMENT_ROOT\'}."/templates"; $blindview = get_cookie("blindview") || 0; %userinfo = (); %section = (); %document = (); $addrubrics = \'\'; $site_admin = 0; $logged_in = 0; $godaccess = 0; $localnet = 0; $have_inet = 0; @treewalk = (); $zx_counter = 0; # Global Redirect Block... if ($servername eq \'arhcity.ru\') { $Response->Redirect("http://$site_url"); } if ($servername eq \'arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } if ($servername eq \'www.arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } # if ($SERVER->{HTTPS} ne \'on\') { # $Response->Redirect("https://www.arhcity.ru/?$SERVER->{QUERY_STRING}"); # } my $ic = Text::Iconv->new("UTF-8", "WINDOWS-1251"); my @r = (); foreach my $i (split(/\\./, $servername)) { if ($i =~ m/^xn--/) { push(@r, puny_dec($i)); } else { push(@r, $i); } } $servername = join(\'.\', @r); $servername = $ic->convert($servername); if ($SERVER->{HTTP_USER_AGENT} =~ m/edge/i) { $useragent = \'edge\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/chrome/i) { $useragent = \'chrome\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/webkit/i) { $useragent = \'safari\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/opera/i) { $useragent = \'opera\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/msie/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/trident/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/mozilla/i) { $useragent = \'mozilla\' } else { $useragent = \'unknown\'; } if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { # read CSS color variables for replace in html code (MSIE/Edge not support CSS vars); my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $CSS_vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); } if (($remoteaddr =~ m/^192\\.168\\./) || ($remoteaddr eq \'212.14.176.38\') || ($remoteaddr eq \'212.14.176.39\') || ($remoteaddr eq \'212.14.176.46\') || ($remoteaddr eq \'212.14.176.40\') || ($remoteaddr eq \'212.14.176.41\') || ($remoteaddr eq \'212.14.176.44\') || ($remoteaddr eq \'195.239.119.234\') # Городской центр гражданской защиты ) { $localnet = 1; } if (($localnet) && ( # Enable extra functions for site admins ($remoteaddr eq \'192.168.1.84\') || # GaidukAV ($remoteaddr eq \'192.168.1.44\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.45\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.46\' ) || # KorzhevDP ($remoteaddr eq \'192.168.51.144\') || # VishnyakovNS ($remoteaddr eq \'192.168.1.102\') || # EkimovKS v.1 ($remoteaddr eq \'192.168.1.110\') || # EkimovKS v.2 ($remoteaddr eq \'192.168.51.42\')) # EkimovKS v.3 ) { $site_admin = 1; } # connect to database $db = DBI->connect($dsn, $username, $password); if (! $db) { print "<p>Database server not responding.<br>Try later.</p>\\n"; $Response->End(); } # ONLY FOR RUSSIAN for MySQL !!! $db->do("set names cp1251"); if ($localnet) { # enable/disable outside scripts on site for local users without inet. ($have_inet) = getonerec("select count(ip) from squid_list where ip = \'$remoteaddr\'"); } else { $have_inet = 1; } # ------------------------------------------------------------ # $have_inet = 0; # !!! disable external scripts on site !!! # ------------------------------------------------------------ if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # !!! admin mode !!! $logged_in = 0; my $uname = $Session->{Authentication}; my $topframe = 0; if ($uname) { # logged in $logged_in = 1; $Session->{top_frame} = 0; my $adm_lib = $admin_dir . "lib/"; if ($SERVER->{\'REQUEST_URI\'} =~ m/$adm_lib/) { # read user info %userinfo = get_user_info($uname); $godaccess = 1 if ($userinfo{god} eq \'Y\'); if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no header } else { $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; } if ($SERVER->{\'REQUEST_URI\'} =~ m/(section.asp)|(page.asp)|(journal.asp)|(admin.asp)/i) { $Response->Include("page_autologoff.asp"); } } } else { # not logged in $topframe = $Session->{top_frame}; if (!$topframe) { my $location = "top.location.href=\'/admin/?t=".time()."\'"; print qq{<script>$location</script>}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n</body>\\n</html>\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with <style></style> definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "<pre>",Dumper(@_),"</pre>\\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n<script>\\n$location\\n</script".">\\n"; } ###################################################################### sub navigator { # отобразить навигатор (путь с корня до страницы) my @a = (\'<a href="/">Начало</a>\'); # if $sid in internal section (#6) - don\'t show any information my $rootsec = @treewalk[$#treewalk]; if ( (!$localnet) && ($rootsec->[0] == 6) ) { # ... } else { foreach my $i (reverse @treewalk) { push(@a, qq{<a href="/?page=$i->[0]/0">$i->[1]</a>}) if ($i->[0] > 0); } } return join(\' <span style="color:red"><img src="/pic/navar.gif" align="baseline"></span> \', @a); } ###################################################################### sub get_config_value { my $varname = shift; my ($varvalue) = getonerec("select varvalue from options where varname = \'$varname\'"); return $varvalue; } ###################################################################### sub store_config_value { my ($varname, $varvalue) = @_; my $query = "update options set varvalue=? where varname=?"; my $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($varvalue, $varname) || print $db->errstr, ", query:[$query]<br>\\n"; $st->finish; } ###################################################################### sub get_user_info { # прочитать информацию о зарегистрированном пользователе (по логину) # return hash my $user = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where username = \'$user\'"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub get_user_id_info { # прочитать информацию о зарегистрированном пользователе (по id) # return hash my $user_id = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where id = $user_id"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub make_pw_hash { # (password) # Создание уникального хэша по паролю my $password = shift; my $letts = \'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\'; my $lettl = length($letts); my $salt = \'\'; $password = substr($password, 0, 32) if (length($password) > 32); # limit password length for my $i (1 .. 5) { $salt .= substr($letts, int(rand() * $lettl), 1); } return $salt.sha1_base64($salt.$password); } ###################################################################### sub check_pw_hash { # (password, pwd_hash) # проверка на соответствие хэша и пароля my $password = shift; my $pw_hash = shift; my $salt = substr($pw_hash, 0, 5); $password = substr($password, 0, 32) if (length($password) > 32); # limit password length return (substr($pw_hash, 5) eq sha1_base64($salt.$password)); } ###################################################################### sub check_auth { # (user, password) # проверка авторизации my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'N\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub check_auth_lc { # (user, password) # проверка авторизации lcab my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'Y\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub get_inherit_tpl { # (sid) # найти имя наследуемого шаблона дизайна my $tpn = "default"; my $tpn2 = \'\'; @treewalk = tree_walk(shift); foreach my $i (reverse(@treewalk)) { if ($i->[2] ne \'\') { $tpn2 = $tpn; $tpn = $i->[2]; } } return ($tpn, $tpn2); } ###################################################################### sub get_tpl_list { # пполучить список доступных шаблонов дизайна my ($c, @ret) = 0; opendir(D, $tpl_dir); while (my $d = readdir(D)) { if ($d =~ m/^(.+)\\.asp$/) { push(@ret, $1); } } closedir(D); return sort @ret; } ###################################################################### sub tree_walk { # ($sid) # пройтись по дереву от указанного раздела до корня, записать в массив ($node, $secname, $sectpl) my ($node, $pnode, $secname, $sectpl, @tw) = shift; my $c = 0; while ($node != 0) { ($node, $pnode, $secname, $sectpl) = getonerec("select sid,secparent,secname,sectpl from section where sid=$node"); push(@tw, ([$node, $secname, $sectpl])); $node = $pnode; $c++; if ($c > 20) { # если очень большое количество итераций - значит в базе ошибка. my $t = \'\'; foreach (@tw) { $t .= \' \'.$_->[0]; } print error("В базе данных ошибка! Возможно зацикленная рекурсия. Срочно обратитесь к администратору.<br>tree_walk: [$t]"); last; } } return @tw; } ###################################################################### sub getonerec { # (query) # прочитать одну запись из базы my ($query, $st, @row) = shift; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]<br>\\n"; $st->execute() || print $db->errstr, ", Q:[$query]<br>\\n"; @row = $st->fetchrow_array; $st->finish; return @row; } ###################################################################### sub get_sql_list { # прочитать список из базы # return @arr = (\'a1\',\'b1\',\'c1\'); my $q = shift; my ($s,@r,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { push(@ret, $r[0]); } $s->finish; return @ret; } ###################################################################### sub get_sql_arr { # прочитать список списков (таблицу) из базы # return @arr = ( [\'a1\',\'a2\'], [\'b1\',\'b2\'], [\'c1\',\'c2\'] ); my $q = shift; my ($s,$rf,@r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { @rt = (); for my $i (0 .. scalar(@r)-1) { $rt[0][$i] = $r[$i]; } push(@ret, @rt); } $s->finish; return @ret; } ###################################################################### sub get_sql_arhash { # (query) # прочитать список хэшей (таблицу с именованными столбцами) из базы # return array of hashes my $q = shift; my ($s,$rf,$r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { push(@ret, $r); } $s->finish; return @ret; } ###################################################################### sub input_text { # ($name, $style, $value) # создать текстовое поле ввода my ($name, $style, $value) = @_; $style .= qq{ id="id$name"} if ($name); my $ret = qq{<input type="text" name="$name" value="$value" $style>}; return $ret; } ###################################################################### sub input_checkbox_1Y { # ($name, $style, $value, $label) # создать поле ввода чекбокс (одиночный) my ($name, $style, $value, $label) = @_; my $ret = ""; my $checked = (($value eq "Y") || ($value eq "on")) ? "checked" : ""; $zx_counter++; $ret = qq{<input type="checkbox" name="$name" id="id$zx_counter$name" $checked $style>&nbsp;<label for="id$zx_counter$name">$label</label>}; return $ret; } ###################################################################### sub input_radio { # ($name, $style, $js, $br, $checked, %values) # создать поле ввода радиоботтон (группу) my ($name, $style, $js, $br, $checked, %values) = @_; my $ret; my $j = ""; foreach my $i (sort keys %values) { if ($js ne \'\') { $j = qq{onclick="$js(\'$i\');"}; } my $checkstr = ($checked eq $i) ? "checked" : ""; $ret .= qq{<input type="radio" name="$name" id="$i" value="$i" $checkstr $style $j>\\n<label for="$i">$values{$i}</label>$br\\n}; } return $ret; } ###################################################################### sub input_textarea { # ($name, $style, $value) # создать поле тексареа my ($name, $style, $value) = @_; my $ret = qq{<textarea name="$name" $style>$value</textarea>}; return $ret; } ###################################################################### sub input_texteditor { # ($name, $imgdir, $value) # создать текстовый редактор на базе FCKeditor my ($name, $imgdir, $value) = @_; my $te = $Response->TrapInclude("page_fckeditor.asp", $name, $imgdir, $value); return $$te; } ###################################################################### sub input_list_arr { # ($name, $style, $currvalue, @arr) # создать поле список из 2d массива, с отключением отображения id # @arr = ( [1,\'a1\'], [2,\'a2\'], [3,\'a3\'] ); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); my $nonum = 0; my $size = qq{size="1"}; $size = $1 if ($style =~ s/(size=["\']*\\d+["\']*)//i); $nonum = 1 if ($style =~ s/nonum//i); $style .= qq{ id="id$name"} if ($name); $ret = qq{<select name="$name" $size $style>\\n}; for my $i (0 .. scalar(@arr)-1) { $sel = \'\'; if ($currvalue =~ m/^\\d+$/) { $sel = "selected" if ($arr[$i][0] == $currvalue); } else { $sel = "selected" if ($arr[$i][0] eq $currvalue); } if ($nonum) { $ret .= qq{<option $sel value="$arr[$i][0]">$arr[$i][1]</option>\\n}; } else { $ret .= qq{<option $sel value="$arr[$i][0]">[$arr[$i][0]] $arr[$i][1]</option>\\n}; } } $ret .= "</select>"; return $ret; } ###################################################################### sub input_list_arr_X1 { # ($name, $style, $currvalue, @arr) # создать поле список из 1d массива # @arr = (\'a1\',\'a2\',\'a3\'); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); $style .= qq{ id="id$name"} if ($name); $ret = "<select name=\\"$name\\" size=\\"1\\" $style>\\n"; foreach my $i (@arr) { if ($i eq $currvalue) { $sel = "selected"; } else { $sel = ""; } $ret .= qq{<option $sel value="$i">$i</option>\\n}; } $ret .= "</select>"; return $ret; } ###################################################################### sub check_acc { # ($sid, $acc_letters) # проверка прав доступа к разделу my ($sid, $acs) = @_; return 1 if ($godaccess); if ($sid =~ m/^\\d+$/) { #my @rghts = get_sql_list("select rights from usersacc where userid=$userinfo{id} and sid=$sid"); my $query = "select usersacc.rights from users inner join usersacc on (users.id = usersacc.userid) where users.enable = \'Y\' and users.id = $userinfo{id} and usersacc.sid = $sid"; my @rghts = get_sql_list($query); my $rights = join(\'\', @rghts); foreach my $ac (split(\'\', $acs)) { return 1 if ($rights =~ m/$ac/); } return 0; } return 0; } ###################################################################### sub tablist { # $sid, $pid, \'tabsheet\', \'focus\', startN, (array of names) # создание панели с закладками (используется в page.asp и section.asp) my ($sid, $pid, $tabsheet_name, $focus_name, $start_page, @pages) = @_; my $pagenum = scalar(@pages)-1; my ($out,$focus1,$focus2); =pod =head1 Параметры вызова: tablist($sid, $pid, \'tabsheet\', \'focus\', startN, (array of names)); =item $sid, $pid Номера раздела и страницы Если номер раздела < 0 - закладка со ссылкой на дерево объектов НЕ отображается. =item \'tabsheet\' HTML Идентификатор панели с табами =item startN Номер закладки, которую нужно открыть при старте страницы Для этого в запросе должен присутствовать параметр "ctsh=N" где N - номер закладки =item \'focus\' Идентификатор HTML объекта для установки фокуса при открытии каждой из закладок =item (array of names) Список строк, являющихся текстом на закладках =head1 Пример реализации панели с табами: <style> #tabsheet0 {display:none} /* в некоторых версяиях браузеров из за ошибки надо комментировать эту строку */ #tabsheet1 {display:none} #tabsheet2 {display:none} .tabsheet { ... } </style> <#% my @tabs = ( \'<img src="/pic/page1.png"> Page One\', \'<img src="/pic/page2.png"> Page Two\', \'<img src="/pic/page3.png"> Page Three\' ); my $ctsh; $ctsh = $FORM->{ctsh}; $ctsh = $QUERY->{ctsh} if ($ctsh eq \'\'); print tablist(-1, \'\', \'tabsheet\', \'fcs\', ($ctsh =~ m/[012]/)?$ctsh:0, @tabs); %#> <div class="tabarea"> <table border="0" width="100%" cellpadding="8" cellspacing="0"><tr><td> <div id="tabsheet0" class="tabsheet">Page 1<br><input type="text" id="fcs0"></div> <div id="tabsheet1" class="tabsheet">Page 2<br><input type="text" id="fcs1"></div> <div id="tabsheet2" class="tabsheet">Page 3<br><input type="text" id="fcs2"></div> </td></tr></table> </div> =cut my $css = qq[ <style> #tablist { padding: 3px 0 3px 6px; margin-left: 0; font: 13px Tahoma; /* line-height: 16px; */ white-space: nowrap; } #tablist li { list-style: none; margin: 0; display: inline; white-space: nowrap; } #tablist li a { color: #555; padding: 3px 6px; margin-left: 3px; border: 1px solid #888; border-bottom: none; background: #ddd; text-decoration: none; font-weight: normal; border-top-left-radius: 6px; border-top-right-radius: 6px; } </style> ]; my $javascript = qq[ <script language="JavaScript"> window.onload = function(){ showTab($start_page); } function showTab(tabnum) { for (i = 0; i <= $pagenum; i++) { document.getElementById(\'$tabsheet_name\'+i).style.display = \'none\'; tln = document.getElementById(\'xtl\'+i); tln.style.color = \'#555\'; tln.style.background = \'#ddd\'; tln.style.borderBottom = \'1px solid #888\'; } var tsheet = document.getElementById(\'$tabsheet_name\'+tabnum); var fcname = document.getElementById(\'$focus_name\'+tabnum); var tln = document.getElementById(\'xtl\'+tabnum); if (tsheet) { tsheet.style.display = \'block\'; } if (fcname) { fcname.focus(); } if (tln) { tln.style.color = \'#000\'; tln.style.background = \'white\'; tln.style.borderBottom = \'1px solid white\'; tln.style.backgroundImage = \'url(/admin/pic/tab_bg.gif)\'; } } </script]; # See ...Perl\\site\\lib\\Apache\\ASP\\GlobalASA.pm, lines 91,92... $out .= $css.$javascript.">\\n"; # stupid bug... $out .= qq{\\n<ul id="tablist" style="margin-bottom:0px;">\\n}; if ($sid > 0) { # отображение закладки со ссылкой на дерево объектов $out .= qq{ <li><a href="treejx.asp?sid=$sid&pid=$pid" style="padding-left:0;margin-left:0;background-color:#20a020;color:#c0ffc0;text-decoration:none" target="treeframe">&nbsp;<acronym title="Отобразить курсор на дереве объектов"><img src="/admin/pic/tree/node-tree.png" class="trico">&nbsp;$sid/$pid&nbsp;</acronym></a></li>\\n}; } for(my $i=0; $i<=$pagenum; $i++) { $pages[0] = qq{<span style="color:blue">$pages[0]</span>} if (($section{sectype} eq \'asp\') || ($sid == 0)); $out .= qq{ <li><a href="#$i" id="xtl$i" onclick="showTab($i)">$pages[$i]</a></li>\\n}; } $out .= qq{</ul>\\n}; return $out; } ####################################################################### sub get_indexgroup_str { # (index_name) # получить строку списка разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return $idx; } ####################################################################### sub get_indexgroup_lst { # (index_name) # получить список разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return split(/,\\s*/, $idx); } ####################################################################### sub exist_in_indexgroup { # ($index_name, $value) # проверить наличие $value в списке разделов по имени my ($index_name, $value) = @_; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return exist_in_list($value, split(/,\\s*/, $idx)); } ###################################################################### sub recalctree { # ($sid) # получить список всех подчиненных разделов от указанного my $sl = shift; $sl =~ s/\\D+/,/g; my @srvindex = (); my ($q, $s, $r); $q = "select sid from section order by sid"; $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { my @tw = (); @treewalk = &tree_walk($r->{sid}); foreach my $item (reverse @treewalk) { push(@tw, $item->[0]); } my %union = (); my %isect = (); # объединение и пересечение множеств @tw и "$sl", результат в %union и %isect foreach my $e (@tw, split(\',\', $sl)) { $union{$e}++ && $isect{$e}++ } push(@srvindex, $r->{sid}) if (scalar(keys %isect)); } $s->finish; return @srvindex; } ####################################################################### sub autorecalctree { # Обновление индексных групп при изменении иерархии разделов my $visual = shift; my ($q1, $s1, $r1); my ($q2, $s2, $r2); print qq{<div id="autoupdate" style="padding-top:10px;">Обновление индексных групп : } if ($visual); $q1 = "select id,slist from srvindex order by id desc"; $s1 = $db->prepare($q1) || print $db->errstr, ", query:[$q1]<br>\\n"; $s1->execute() || print $db->errstr, ", query:[$q1]<br>\\n"; while ( $r1 = $s1->fetchrow_hashref ) { print qq{<span style="background-color:blue;color:white">&nbsp;$r1->{id}&nbsp;</span>&nbsp;} if ($visual); $Response->Flush() if ($visual); # anti timeout solution my $flist = join(\',\', recalctree($r1->{slist})); $q2 = "update srvindex set flist=? where id=$r1->{id}"; $s2 = $db->prepare($q2) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->execute($flist) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->finish; } $s1->finish; print qq{\\n</div>\\n<style>#autoupdate {display:none} </style>\\n} if ($visual); } ####################################################################### sub check_for_secdel { # (sid) # проверка возможности удаления раздела my ($sid) = @_; my @cd_msg = (); my ($cs, $cp, $cf) = (0, 0, 0); my $filedir = "$uploaddir/$sid"; # считаем количество подразделов ($cs) = getonerec("select count(sid) from section where secparent = $sid"); push(@cd_msg, "Разделов: <span style=\'color:red\'>$cs</span>") if ($cs); # считаем количество документов в разделе ($cp) = getonerec("select count(pid) from documents where sid = $sid"); push(@cd_msg, "Страниц: <span style=\'color:red\'>$cp</span>") if ($cp); # считаем количество файлов в разделе if (opendir(D, $filedir)) { my @rm_dir = readdir(D); closedir(D); $cf = scalar(@rm_dir); # уменьшаем $cf из за служебных папок: \'.\' и \'..\' foreach my $d (@rm_dir) { $cf-- if ($d =~ m/^\\.+$/); } } push(@cd_msg, "Файлов: <span style=\'color:red\'>$cf</span>") if ($cf); return @cd_msg; } ###################################################################### sub get_section { # (sid) # прочитать информацию о разделе # return hash my ($sid) = @_; my (%ret, $query, $st, $row) = (); if ($sid > 0) { $query = "select * from section where sid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; } return %ret; } ###################################################################### sub get_document { # (sid, pid) # прочитать документ # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); $query = "select * from documents where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; $st->finish; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } return %ret; } ###################################################################### sub get_document_ex { # (sid, pid) # прочитать документ с расширенными полями # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); %ret = get_document($sid, $pid); $query = "select field,value from documents_ex where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { $ret{$row->{field}} = $row->{value}; } $st->finish; return %ret; } ###################################################################### sub get_sec_documents { # (sid, \'body\') # прочитать все документы раздела (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body) = @_; my (@ret, $query, $st, $row, $b) = (); $b = \'pagebody,\' if ($body); my $fields = "sid,pid,userid,url,pagename,".$b."pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus"; $query = "select $fields from documents where sid=? order by pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; return @ret; } ###################################################################### sub get_sec_documents_ex { # (sid, body, x_where) # прочитать все документы раздела с расширенными полями (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body, $x_where) = @_; my (@ret, @ret_ex, $query, $st, $row, $b) = (); $b = \'documents.pagebody,\' if ($body); my $fields = " documents.sid, documents.pid, documents.userid, documents.url, documents.pagename, $b documents.pagedate, documents.pagemodify, documents.pageorder, documents.sh_hdr, documents.sh_dir, documents.sh_nav, documents.sh_tab, documents.docstatus, documents_ex.field, documents_ex.value"; $query = "select $fields from documents left outer join documents_ex on (documents_ex.sid = documents.sid) and (documents_ex.pid = documents.pid) where documents.sid = $sid"; $query = "$query and ($x_where)" if ($x_where); # open(F, ">>$site_path/asa/q.log"); # print F "get_sec_documents_ex: $query\\n\\n"; # close(F); $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute() || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; # получили массив @ret с дублями строк для полей из documents my %h = (); foreach my $i (@ret) { # чтобы избавится от дублей пихаем строки в хэш, где ключ = \'sid.pid\' if (!defined($h{"$i->{sid}.$i->{pid}"})) { $h{"$i->{sid}.$i->{pid}"} = { \'sid\' => $i->{\'sid\'}, \'pid\' => $i->{\'pid\'}, \'userid\' => $i->{\'userid\'}, \'url\' => $i->{\'url\'}, \'pagename\' => $i->{\'pagename\'}, \'pagedate\' => $i->{\'pagedate\'}, \'pagemodify\' => $i->{\'pagemodify\'}, \'pageorder\' => $i->{\'pageorder\'}, \'sh_hdr\' => $i->{\'sh_hdr\'}, \'sh_dir\' => $i->{\'sh_dir\'}, \'sh_nav\' => $i->{\'sh_nav\'}, \'sh_tab\' => $i->{\'sh_tab\'}, \'docstatus\' => $i->{\'docstatus\'}, $i->{\'field\'} => $i->{\'value\'}, }; } else { # в случае сущесвования такой же строки в хэше - добавляем очередное поле из documents_ex $h{"$i->{sid}.$i->{pid}"}->{$i->{\'field\'}} = $i->{\'value\'}; } } @ret = (); # перекидываем всё из хэша в массив foreach my $i (keys %h) { push(@ret, $h{$i}); } return @ret; } ###################################################################### sub create_document { # (sid, userid, hash_fields) # создать документ в указанном разделе my ($sid, $userid, %fields) = @_; my ($pid, $query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # search new $pid for $sid my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $pid++; # set default values for new document $fields{pageorder} = $pid * 10; # insert new fields of document $query = "insert into documents (sid,pid,userid,url,pagename,pagebody,pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'create_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_document_ex { # (sid, userid, hash_fields) # создать документ с расширенными полями в указанном разделе my ($sid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { create_document($sid, $userid, %fields); my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $fields{pagebody} = \'\'; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'create_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document { # ($sid, $pid, $userid) # удалить документ my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document_ex { # ($sid, $pid, $userid) # удалить документ с расширенными полями my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); my %fields_ex = get_document_ex($sid, $pid); $query = "delete from documents_ex where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = \'\'; foreach my $i (keys %fields_ex) { $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'delete_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_section { # (sid) # удалить раздел my ($sid) = @_; my ($st, $query); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { $query = "delete from section where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); # remove rights for deleted section $query = "delete from usersacc where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document { # (sid, pid, userid, hash_fields) # заменить документ my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # update fields of document $query = "update documents set userid=?,url=?,pagename=?,pagebody=?,pagedate=?,pagemodify=?,pageorder=?,sh_hdr=?,sh_dir=?,sh_nav=?,sh_tab=?,docstatus=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'replace_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document_ex { # (sid, pid, userid, hash_fields) # заменить документ с расширенными полями my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { replace_document($sid, $pid, $userid, %fields); $fields{pagebody} = \'\'; # delete \'_ex\' fields in documents_ex $query = "delete from documents_ex where sid = $sid and pid = $pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]== $fields_ex{$i}\\n"; } journaldata(\'replace_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_section { # (hash_fields) # создать раздел my (%fields) = @_; my ($st, $sid, $query); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($secorder) = getonerec("select max(secorder) from section where secparent=$FORM->{secparent}"); $secorder = $secorder + 10; $fields{sectype} = $fields{sectype} || \'table\'; $fields{sorttype} = $fields{sorttype} || \'az\'; # insert record of section $query = "insert into section (secparent,secname,secdescr,sectype,plug_view,plug_admn,plug_ico,startpage,sorttype,secorder,sh_nav,sh_dir,sh_hdr) values (?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secparent}, $fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, ($fields{sectype} eq \'table\') ? $fields{startpage} : 0, $fields{sorttype}, $secorder, ($fields{sh_nav} eq "on") ? "Y" : "N", ($fields{sh_dir} eq "on") ? "Y" : "N", ($fields{sh_hdr} eq "on") ? "Y" : "N", ) || print $db->errstr, ", query:[$query]<br>\\n"; $sid = $db->{\'mysql_insertid\'}; logdata($query); # delete all rights for new section $query = "delete from usersacc where sid=$sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # copy rights from parent to current section $query = "insert into usersacc (userid,sid,rights) select userid,$sid,rights from usersacc where sid=$FORM->{secparent}"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return $sid; } ###################################################################### sub update_section { # (sid, hash_fields) # изменить раздел my ($sid, %fields) = @_; my ($st, $query); $fields{secparent} = 0 if (!defined($fields{secparent})); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); return -5 if (($fields{sectype} eq \'table\') && ($fields{startpage} !~ m/^\\-*\\d+$/)); return -6 if ($fields{secorder} !~ m/^\\d+$/); $fields{sorttype} = $fields{sorttype} || \'az\'; $fields{sh_nav} = ($fields{sh_nav} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_dir} = ($fields{sh_dir} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_hdr} = ($fields{sh_hdr} =~ m/on|Y/) ? \'Y\' : \'N\'; if ($fields{sectype} eq \'table\') { $fields{plug_view} = \'\'; $fields{plug_admn} = \'\'; $fields{plug_ico} = \'\'; } elsif ($fields{sectype} eq \'asp\') { $fields{startpage} = 0; } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { if ($godaccess) { # only GODS may change fields: \'plug_view, plug_admn, plug_ico, sec_tpl\' $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, plug_view=?, plug_admn=?, plug_ico=?, sectpl=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, $fields{template}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } else { $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub move_document { # ($sid, $pid, $new_sid, $userid) # переместить документ в другой раздел my ($sid, $pid, $new_sid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($new_pid, $new_pageorder) = getonerec("select max(pid),max(pageorder) from documents where sid=$new_sid"); $new_pid++; $new_pageorder = $new_pageorder + 10; my %fields = get_document($sid, $pid); $query = "update documents set userid=?, sid=?, pid=?, pageorder=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($userid, $new_sid, $new_pid, $new_pageorder) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = "Change: <b>$sid/$pid</b> to <b>$new_sid/$new_pid</b>"; journaldata(\'move_document\', $new_sid, $new_pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub journaldata { # ($func, $sid, $pid, $userid, %fields) # записать в журнал документ/раздел/сообщение my ($func, $sid, $pid, $userid, %fields) = @_; my $query = "insert into journal (ipaddr,function,sid,pid,userid,url,pagename,pagebody,pagedate,docstatus) values (?,?,?,?,?,?,?,?,?,?)"; my $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($remoteaddr, $func, $sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; } ###################################################################### sub cutwords { # ($string, $numwords) # отрезать от новостного сообщения начало в $numwords слов my ($str, $nw) = @_; my $ret; $str =~ s!<p(.*?)>! <p$1>!i; $str =~ s!<br>! <br>!i; $str =~ s!<div(.*?)>! <div$1>!i; $str =~ s!<(/*strong)>!%%$1%%!gi; $str =~ s!<(/*)b>!%%$1strong%%!gi; $str =~ s!<img (.+?)>!%%img $1%%!i; $str =~ s/(<(?=!--)([^>]|\\n)*--(?=>)>)//ig; $str =~ s/|(<\\/?([^>]|\\n)*>)//g; $str =~ s/&nbsp;/ /g; $str =~ s/\\s+/ /g; $str =~ s!%%(/*strong)%%!<$1>!gi; $str =~ s!%%img (.+?)%%!<img $1>!i; my @a = split(/\\s/, $str); if ($#a > $nw) { $ret = join(\' \', splice(@a, 0, $nw)) . qq{<b> . . .</b>}; } else { $ret = $str; } if (($ret =~ m!<strong>!) && ($ret !~ m!</strong>!)) { $ret .= "</strong>"; } return $ret; } ###################################################################### sub round { # округлить значение my $i = shift; return $i - int($i) < 0.5 ? int($i) : int($i)+1; } ###################################################################### sub rss_expand_img_url { # разворачивает URL картинки для RSS my ($u1, $u2, $u3) = @_; return "<img $u1"."src=\\"http://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_expand_hrf_url { # разворачивает URL ссылки для RSS my ($u1, $u2, $u3) = @_; return "<a $u1"."href=\\"https://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_clear_html_to_xml { # причесывает страницу по правилам XML my $txt = shift; $txt =~ s/<img (.*?)src="(.+?)"(.*?)>/rss_expand_img_url($1,$2,$3)/ige; $txt =~ s/<a (.*?)href="(.+?)"(.*?)>/rss_expand_hrf_url($1,$2,$3)/ige; $txt =~ s/&nbsp;/ /g; $txt =~ s/\\s+/ /g; $txt =~ s/&/&amp;/g; $txt =~ s/</&lt;/gi; return $txt; } ###################################################################### sub get_root_category { # для текущего раздела (что в последнем элементе массива @treewalk) ищет предка, у которого родитель = 4 if (@treewalk) { if (@treewalk[scalar(@treewalk)-1]->[0] == 4) { return @treewalk[scalar(@treewalk)-2]->[1]; } else { return @treewalk[scalar(@treewalk)-1]->[1]; } } else { return ""; } } ###################################################################### sub send_mail_smtp { # ($host, $from, $to, $body) my ($_host, $_from, $_to, $_xbody) = @_; $_xbody = "To: $_to\\n$_xbody"; my $smtp = Net::SMTP->new($_host, Hello => \'mail.arhcity.ru\', Timeout => 30); $smtp->mail($_from); $smtp->to($_to); $smtp->data(); $smtp->datasend($_xbody); $smtp->dataend(); $smtp->quit; } ###################################################################### sub get_cookie { # возвращает значение куки по ключу (см. \\asp\\admin\\lib\\adminlib.js) my $name = shift; my $cook = $SERVER->{HTTP_COOKIE}; my @arr = split(/;\\s*/, $cook); my %ck = (); foreach my $c (@arr) { my ($k, $v) = split(/=/, $c); $ck{$k} = $v; } return $ck{$name}; } ###################################################################### sub random_str { # возвращает строку указанной длинны (или 5) из случайных символов my $len = shift || 5; my $c = \'0123456789abcdefghijklmnopqrstuvwxyz\'; my $l = length($c); my $s = \'\'; for (1 .. $len) { $s .= substr($c, int(rand()*$l), 1); } return $s; } ###################################################################### sub check_body_style { # ( body ) my $body = shift; my (@cb_arr, @ret_txt) = (); @cb_arr = (); @cb_arr = $body =~ m!<(img|a).* (src|href)="data:image/(gif|png|jpeg);base64,(\\S+)"!sg; push(@ret_txt, "&bull; Недопустимое применение ссылок формата \\"data:image\\" (".(scalar(@cb_arr)/4)." раз.)") if (@cb_arr > 0); @cb_arr = (); @cb_arr = $body =~ m/<w:LsdException/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'LsdException\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/<w:WordDocument>/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'WordDocument\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/text-indent:27\\.0pt|class="MsoNormal"|tab-stops:list -9\\.0pt|mso-layout-grid-align:/sg; push(@ret_txt, "&bull; В тексте присутствуют инлайн-стили от Microsoft Word (".scalar(@cb_arr)." раз.)") if (@cb_arr > 4); @cb_arr = (); @cb_arr = $body =~ m/style="font-family: \'Times New Roman\'/sg; push(@ret_txt, "&bull; Слишком частое использование шрифта \'Times New Roman\' (".scalar(@cb_arr)." раз.)") if (@cb_arr > 5); @cb_arr = (); @cb_arr = $body =~ m/<span style="color: .+?;">|<span style="background-color: rgb(255, 255, 255);">/sg; push(@ret_txt, "&bull; Частое/неуместное использование цветового выделения (".scalar(@cb_arr)." раз.)") if (@cb_arr > 8); if (@ret_txt) { return join("<br>\\n", @ret_txt); } else { return 0; } } ###################################################################### sub meta_og_tags { # возвращает "Open Graph" тэги для страницы my ($sid, $pid) = @_; my $pageheader = $section{secname}; $pageheader = "Городские новости" if ($sid == 0); # https://ruogp.me/ - Протокол Open Graph my $r = \'\'; $r .= qq{<meta property="og:site_name" content="Администрация города Архангельска" />\\n}; $r .= qq{<meta property="og:url" content="http://arhcity.ru/?page=$sid/$pid" />\\n}; $r .= qq{<meta property="og:title" content="$pageheader" />\\n}; $r .= qq{<meta property="og:description" content="$document{pagename}" />\\n}; $r .= qq{<meta property="og:image" content="http://arhcity.ru/pic/og-image-arhcity.jpg" />\\n}; if ($section{sectype} eq \'table\') { my $_r = \'\'; my $c = 0; my @og_image = $document{pagebody} =~ m!<img src="(.+?)" .+/>!g; foreach my $i (@og_image) { $i =~ s!http://.+?\\.ru!!g; $_r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; $c++; } if ($c > 5) { # если картинок на странице много ( >5 ) - показываем только первую my $i = @og_image[0]; $i =~ s!http://.+?\\.ru!!g; $r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; } else { $r = $_r; } } return $r; } ###################################################################### sub gen_int_EO { # (number) # возвращает случайное чётное/нечётное число в интервале 0..number в зависимости от чётности number my $n = shift; my $r = int(rand() * $n); if ($n % 2 == 0) { $r++ if ($r % 2 == 1); } else { $r++ if ($r % 2 == 0); } return $r; } ###################################################################### sub update_msie_css { # внедряем в default.css значения переменных из colors.css и создаём default-ie.css my $ret = 0; my %vars = (); my $default_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default.css"; my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; my $default_ie_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default-ie.css"; my ($t_default_css) = (stat($default_css_fn))[9]; my ($t_colors_css) = (stat($colors_css_fn))[9]; my ($t_default_ie_css) = (stat($default_ie_css_fn))[9]; if (($t_default_css > $t_default_ie_css) || ($t_colors_css > $t_default_ie_css)) { open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); open(FS, "< $default_css_fn") || die "Can\'t open $default_css_fn, $!\\n"; open(FO, "> $default_ie_css_fn") || die "Can\'t open $default_ie_css_fn, $!\\n"; while (my $l = <FS>) { next if ($l =~ m/colors.css/); $l =~ s/(var\\((--.+?)\\))/exists($vars{$2})?$vars{$2}:\'none\'/gsex; print FO $l; } close(FO); close(FS); } $ret = 1 if ((stat($default_ie_css_fn))[7] > 0); # if filesize $default_ie_css_fn > 0 - file OK. return $ret; } ###################################################################### ## XML subroutines ################################################### ###################################################################### # see http://www.arhcity.ru/1.asp # ###################################################################### sub ipcms::button { my ($args, $html) = @_; my ($ico, $spacer); if (( $args->{ico}) && ( $args->{txt})) { $spacer = \'&nbsp;\'; } if ((!$args->{ico}) && ( $args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="1" height="16">\'; } if (( $args->{ico}) && (!$args->{txt})) { $spacer = \'\'; } if ((!$args->{ico}) && (!$args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="16" height="16">\'; } if ($args->{ico}) { $ico = qq{<img src="$args->{ico}" width="16" height="16">}; } print qq{<a href="$args->{url}"><div class="shbutton">}.$ico.$spacer.$args->{txt}.qq{</div></a>}; } ###################################################################### sub ipcms::panel { my ($args, $html) = @_; my ($o_style, $style); $o_style = $args->{style} if ($args->{style}); $style = qq{ style="$o_style"} if ($o_style); print qq{<div class="border_area"$style>$html<br>}; print_dump($args); print qq{</div>\\n}; } ;; sub exit { $main::Response->End(); } ;; no lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; 1;' called at /usr/local/share/perl5/Apache/ASP/GlobalASA.pm line 122 Apache::ASP::GlobalASA::new('Apache::ASP=HASH(0x562e3465c280)') called at /usr/local/share/perl5/Apache/ASP.pm line 389 Apache::ASP::new('Apache::ASP', 'Apache2::RequestRec=SCALAR(0x562e342fd2a8)', '/var/www/HDD2/mc.arhcity.ru/asp/index.asp') called at /usr/local/share/perl5/Apache/ASP.pm line 184 Apache::ASP::handler('Apache2::RequestRec=SCALAR(0x562e342fd2a8)') called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 eval {...} called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 BEGIN failed--compilation aborted at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12. at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12. eval ' #line 1 /var/www/HDD2/mc.arhcity.ru/asa/global.asa package Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax; ;; use strict ;; use vars qw($Application $Session $Response $Server $Request); ;; use lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; #!/usr/bin/perl use Time::HiRes qw(gettimeofday tv_interval); use Apache::DBI; # automatic persistent database connections use DBI; use HTTP::Date; use Digest::SHA1 qw(sha1_hex sha1_base64); use Socket; use URI::UTF8::Punycode; use APR::UUID; use Text::Iconv; use Net::SMTP; # when PerlSetVar UseStrict setting on, need to declare # global variables with "use vars" ################################################################## # declare global variables use vars (\'$db\', # database interface \'$FORM\', # form data, method POST \'$QUERY\', # form data, method GET \'$POST\', # unformat form data, method POST \'$SERVER\', # server variables \'$localnet\', # access from local network \'$have_inet\', # access to internet \'$remoteaddr\', # remote IP address \'$useragent\', # UserAgent () \'$site_admin\', # Enable extra functions for site admins \'$logged_in\', # admin access by session \'$lc_logged_in\', # private cabinet access by session \'$servername\', # name of server \'$addrubrics\', # additional menu "rubrics" \'$tpl_dir\', # html template directory \'$godaccess\', # GOD access \'$hires_time\', # time generation of page ############################# \'%userinfo\', # entrie user data (hash) \'%section\', # entrie section data (hash) \'%document\', # entrie document data (hash) ############################# \'@treewalk\', # walking from leaf to root = ([$node, $secname, $sectpl]) \'%mod_params\', # parameters for plugins \'$zx_counter\', # counter for all unique repitable operations \'$site_url\', # url to site \'$site_path\', # path to site location \'$blindview\', # blind vew mode \'%CSS_vars\', # CSS variables ); ################################################################## my $host = \'localhost\'; my $db_name = \'ipcms3\'; my $dsn = "DBI:mysql:database=$db_name:host=$host"; my $username = \'root\'; my $password = \'\'; ################################################################## my $log_file; my $uploaddir; my $admin_dir = "/admin/"; my $lcab = "/lc/"; # list of datastore fields for separate \'_ex\' and non \'_ex\' fields my @doc_fields = qw(sid pid userid url pagename pagebody pagedate pagemodify pageorder sh_hdr sh_dir sh_nav sh_tab docstatus rating1 rating2); # at the begining of the page execution sub Script_OnStart { $hires_time = [gettimeofday]; $Response->Include("site_setup.asp"); # get default values for current site $log_file = "$site_path/datafiles/ipcms3.log"; $uploaddir = "$site_path/asp/data"; $Response->{\'ContentType\'} = "text/html"; $Response->{\'Charset\'} = "Windows-1251"; # $Response->{\'Expires\'} = 0; # page expired after NN seconds from download. # $Response->{\'Last-Modified:\'} = time2str(time-1); $FORM = $Request->Form(); $QUERY = $Request->QueryString(); # $POST = $Request->BinaryRead($Request->ServerVariables(\'CONTENT_LENGTH\')); # for debug $SERVER = $Request->ServerVariables(); $remoteaddr = $SERVER->{\'REMOTE_ADDR\'}; $servername = $SERVER->{\'SERVER_NAME\'}; $tpl_dir = $SERVER->{\'DOCUMENT_ROOT\'}."/templates"; $blindview = get_cookie("blindview") || 0; %userinfo = (); %section = (); %document = (); $addrubrics = \'\'; $site_admin = 0; $logged_in = 0; $godaccess = 0; $localnet = 0; $have_inet = 0; @treewalk = (); $zx_counter = 0; # Global Redirect Block... if ($servername eq \'arhcity.ru\') { $Response->Redirect("http://$site_url"); } if ($servername eq \'arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } if ($servername eq \'www.arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } # if ($SERVER->{HTTPS} ne \'on\') { # $Response->Redirect("https://www.arhcity.ru/?$SERVER->{QUERY_STRING}"); # } my $ic = Text::Iconv->new("UTF-8", "WINDOWS-1251"); my @r = (); foreach my $i (split(/\\./, $servername)) { if ($i =~ m/^xn--/) { push(@r, puny_dec($i)); } else { push(@r, $i); } } $servername = join(\'.\', @r); $servername = $ic->convert($servername); if ($SERVER->{HTTP_USER_AGENT} =~ m/edge/i) { $useragent = \'edge\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/chrome/i) { $useragent = \'chrome\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/webkit/i) { $useragent = \'safari\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/opera/i) { $useragent = \'opera\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/msie/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/trident/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/mozilla/i) { $useragent = \'mozilla\' } else { $useragent = \'unknown\'; } if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { # read CSS color variables for replace in html code (MSIE/Edge not support CSS vars); my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $CSS_vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); } if (($remoteaddr =~ m/^192\\.168\\./) || ($remoteaddr eq \'212.14.176.38\') || ($remoteaddr eq \'212.14.176.39\') || ($remoteaddr eq \'212.14.176.46\') || ($remoteaddr eq \'212.14.176.40\') || ($remoteaddr eq \'212.14.176.41\') || ($remoteaddr eq \'212.14.176.44\') || ($remoteaddr eq \'195.239.119.234\') # Городской центр гражданской защиты ) { $localnet = 1; } if (($localnet) && ( # Enable extra functions for site admins ($remoteaddr eq \'192.168.1.84\') || # GaidukAV ($remoteaddr eq \'192.168.1.44\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.45\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.46\' ) || # KorzhevDP ($remoteaddr eq \'192.168.51.144\') || # VishnyakovNS ($remoteaddr eq \'192.168.1.102\') || # EkimovKS v.1 ($remoteaddr eq \'192.168.1.110\') || # EkimovKS v.2 ($remoteaddr eq \'192.168.51.42\')) # EkimovKS v.3 ) { $site_admin = 1; } # connect to database $db = DBI->connect($dsn, $username, $password); if (! $db) { print "<p>Database server not responding.<br>Try later.</p>\\n"; $Response->End(); } # ONLY FOR RUSSIAN for MySQL !!! $db->do("set names cp1251"); if ($localnet) { # enable/disable outside scripts on site for local users without inet. ($have_inet) = getonerec("select count(ip) from squid_list where ip = \'$remoteaddr\'"); } else { $have_inet = 1; } # ------------------------------------------------------------ # $have_inet = 0; # !!! disable external scripts on site !!! # ------------------------------------------------------------ if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # !!! admin mode !!! $logged_in = 0; my $uname = $Session->{Authentication}; my $topframe = 0; if ($uname) { # logged in $logged_in = 1; $Session->{top_frame} = 0; my $adm_lib = $admin_dir . "lib/"; if ($SERVER->{\'REQUEST_URI\'} =~ m/$adm_lib/) { # read user info %userinfo = get_user_info($uname); $godaccess = 1 if ($userinfo{god} eq \'Y\'); if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no header } else { $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; } if ($SERVER->{\'REQUEST_URI\'} =~ m/(section.asp)|(page.asp)|(journal.asp)|(admin.asp)/i) { $Response->Include("page_autologoff.asp"); } } } else { # not logged in $topframe = $Session->{top_frame}; if (!$topframe) { my $location = "top.location.href=\'/admin/?t=".time()."\'"; print qq{<script>$location</script>}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n<body>\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n</body>\\n</html>\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with <style></style> definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "<pre>",Dumper(@_),"</pre>\\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n<script>\\n$location\\n</script".">\\n"; } ###################################################################### sub navigator { # отобразить навигатор (путь с корня до страницы) my @a = (\'<a href="/">Начало</a>\'); # if $sid in internal section (#6) - don\'t show any information my $rootsec = @treewalk[$#treewalk]; if ( (!$localnet) && ($rootsec->[0] == 6) ) { # ... } else { foreach my $i (reverse @treewalk) { push(@a, qq{<a href="/?page=$i->[0]/0">$i->[1]</a>}) if ($i->[0] > 0); } } return join(\' <span style="color:red"><img src="/pic/navar.gif" align="baseline"></span> \', @a); } ###################################################################### sub get_config_value { my $varname = shift; my ($varvalue) = getonerec("select varvalue from options where varname = \'$varname\'"); return $varvalue; } ###################################################################### sub store_config_value { my ($varname, $varvalue) = @_; my $query = "update options set varvalue=? where varname=?"; my $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($varvalue, $varname) || print $db->errstr, ", query:[$query]<br>\\n"; $st->finish; } ###################################################################### sub get_user_info { # прочитать информацию о зарегистрированном пользователе (по логину) # return hash my $user = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where username = \'$user\'"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub get_user_id_info { # прочитать информацию о зарегистрированном пользователе (по id) # return hash my $user_id = shift; my (%ret, $query, $st, $row) = (); $query = "select * from users where id = $user_id"; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]\\n"; $st->execute() || print $db->errstr, ", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; return %ret; } ###################################################################### sub make_pw_hash { # (password) # Создание уникального хэша по паролю my $password = shift; my $letts = \'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\'; my $lettl = length($letts); my $salt = \'\'; $password = substr($password, 0, 32) if (length($password) > 32); # limit password length for my $i (1 .. 5) { $salt .= substr($letts, int(rand() * $lettl), 1); } return $salt.sha1_base64($salt.$password); } ###################################################################### sub check_pw_hash { # (password, pwd_hash) # проверка на соответствие хэша и пароля my $password = shift; my $pw_hash = shift; my $salt = substr($pw_hash, 0, 5); $password = substr($password, 0, 32) if (length($password) > 32); # limit password length return (substr($pw_hash, 5) eq sha1_base64($salt.$password)); } ###################################################################### sub check_auth { # (user, password) # проверка авторизации my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'N\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub check_auth_lc { # (user, password) # проверка авторизации lcab my ($u, $p) = @_; $u =~ s/[\\;\\,\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\-\\+\\=\\\'\\"\\[\\{\\(\\)\\}\\]\\/\\\\]//g; my ($ph) = getonerec("select passwd from users where lc = \'Y\' and enable=\'Y\' and username = \'$u\'"); return 1 if (check_pw_hash($p, $ph)); return 0; } ###################################################################### sub get_inherit_tpl { # (sid) # найти имя наследуемого шаблона дизайна my $tpn = "default"; my $tpn2 = \'\'; @treewalk = tree_walk(shift); foreach my $i (reverse(@treewalk)) { if ($i->[2] ne \'\') { $tpn2 = $tpn; $tpn = $i->[2]; } } return ($tpn, $tpn2); } ###################################################################### sub get_tpl_list { # пполучить список доступных шаблонов дизайна my ($c, @ret) = 0; opendir(D, $tpl_dir); while (my $d = readdir(D)) { if ($d =~ m/^(.+)\\.asp$/) { push(@ret, $1); } } closedir(D); return sort @ret; } ###################################################################### sub tree_walk { # ($sid) # пройтись по дереву от указанного раздела до корня, записать в массив ($node, $secname, $sectpl) my ($node, $pnode, $secname, $sectpl, @tw) = shift; my $c = 0; while ($node != 0) { ($node, $pnode, $secname, $sectpl) = getonerec("select sid,secparent,secname,sectpl from section where sid=$node"); push(@tw, ([$node, $secname, $sectpl])); $node = $pnode; $c++; if ($c > 20) { # если очень большое количество итераций - значит в базе ошибка. my $t = \'\'; foreach (@tw) { $t .= \' \'.$_->[0]; } print error("В базе данных ошибка! Возможно зацикленная рекурсия. Срочно обратитесь к администратору.<br>tree_walk: [$t]"); last; } } return @tw; } ###################################################################### sub getonerec { # (query) # прочитать одну запись из базы my ($query, $st, @row) = shift; $st = $db->prepare($query) || print $db->errstr, ", Q:[$query]<br>\\n"; $st->execute() || print $db->errstr, ", Q:[$query]<br>\\n"; @row = $st->fetchrow_array; $st->finish; return @row; } ###################################################################### sub get_sql_list { # прочитать список из базы # return @arr = (\'a1\',\'b1\',\'c1\'); my $q = shift; my ($s,@r,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { push(@ret, $r[0]); } $s->finish; return @ret; } ###################################################################### sub get_sql_arr { # прочитать список списков (таблицу) из базы # return @arr = ( [\'a1\',\'a2\'], [\'b1\',\'b2\'], [\'c1\',\'c2\'] ); my $q = shift; my ($s,$rf,@r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( @r = $s->fetchrow_array ) { @rt = (); for my $i (0 .. scalar(@r)-1) { $rt[0][$i] = $r[$i]; } push(@ret, @rt); } $s->finish; return @ret; } ###################################################################### sub get_sql_arhash { # (query) # прочитать список хэшей (таблицу с именованными столбцами) из базы # return array of hashes my $q = shift; my ($s,$rf,$r,@rt,@ret); $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { push(@ret, $r); } $s->finish; return @ret; } ###################################################################### sub input_text { # ($name, $style, $value) # создать текстовое поле ввода my ($name, $style, $value) = @_; $style .= qq{ id="id$name"} if ($name); my $ret = qq{<input type="text" name="$name" value="$value" $style>}; return $ret; } ###################################################################### sub input_checkbox_1Y { # ($name, $style, $value, $label) # создать поле ввода чекбокс (одиночный) my ($name, $style, $value, $label) = @_; my $ret = ""; my $checked = (($value eq "Y") || ($value eq "on")) ? "checked" : ""; $zx_counter++; $ret = qq{<input type="checkbox" name="$name" id="id$zx_counter$name" $checked $style>&nbsp;<label for="id$zx_counter$name">$label</label>}; return $ret; } ###################################################################### sub input_radio { # ($name, $style, $js, $br, $checked, %values) # создать поле ввода радиоботтон (группу) my ($name, $style, $js, $br, $checked, %values) = @_; my $ret; my $j = ""; foreach my $i (sort keys %values) { if ($js ne \'\') { $j = qq{onclick="$js(\'$i\');"}; } my $checkstr = ($checked eq $i) ? "checked" : ""; $ret .= qq{<input type="radio" name="$name" id="$i" value="$i" $checkstr $style $j>\\n<label for="$i">$values{$i}</label>$br\\n}; } return $ret; } ###################################################################### sub input_textarea { # ($name, $style, $value) # создать поле тексареа my ($name, $style, $value) = @_; my $ret = qq{<textarea name="$name" $style>$value</textarea>}; return $ret; } ###################################################################### sub input_texteditor { # ($name, $imgdir, $value) # создать текстовый редактор на базе FCKeditor my ($name, $imgdir, $value) = @_; my $te = $Response->TrapInclude("page_fckeditor.asp", $name, $imgdir, $value); return $$te; } ###################################################################### sub input_list_arr { # ($name, $style, $currvalue, @arr) # создать поле список из 2d массива, с отключением отображения id # @arr = ( [1,\'a1\'], [2,\'a2\'], [3,\'a3\'] ); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); my $nonum = 0; my $size = qq{size="1"}; $size = $1 if ($style =~ s/(size=["\']*\\d+["\']*)//i); $nonum = 1 if ($style =~ s/nonum//i); $style .= qq{ id="id$name"} if ($name); $ret = qq{<select name="$name" $size $style>\\n}; for my $i (0 .. scalar(@arr)-1) { $sel = \'\'; if ($currvalue =~ m/^\\d+$/) { $sel = "selected" if ($arr[$i][0] == $currvalue); } else { $sel = "selected" if ($arr[$i][0] eq $currvalue); } if ($nonum) { $ret .= qq{<option $sel value="$arr[$i][0]">$arr[$i][1]</option>\\n}; } else { $ret .= qq{<option $sel value="$arr[$i][0]">[$arr[$i][0]] $arr[$i][1]</option>\\n}; } } $ret .= "</select>"; return $ret; } ###################################################################### sub input_list_arr_X1 { # ($name, $style, $currvalue, @arr) # создать поле список из 1d массива # @arr = (\'a1\',\'a2\',\'a3\'); my ($name, $style, $currvalue, @arr) = @_; my ($ret, $sel) = (\'\', \'\'); $style .= qq{ id="id$name"} if ($name); $ret = "<select name=\\"$name\\" size=\\"1\\" $style>\\n"; foreach my $i (@arr) { if ($i eq $currvalue) { $sel = "selected"; } else { $sel = ""; } $ret .= qq{<option $sel value="$i">$i</option>\\n}; } $ret .= "</select>"; return $ret; } ###################################################################### sub check_acc { # ($sid, $acc_letters) # проверка прав доступа к разделу my ($sid, $acs) = @_; return 1 if ($godaccess); if ($sid =~ m/^\\d+$/) { #my @rghts = get_sql_list("select rights from usersacc where userid=$userinfo{id} and sid=$sid"); my $query = "select usersacc.rights from users inner join usersacc on (users.id = usersacc.userid) where users.enable = \'Y\' and users.id = $userinfo{id} and usersacc.sid = $sid"; my @rghts = get_sql_list($query); my $rights = join(\'\', @rghts); foreach my $ac (split(\'\', $acs)) { return 1 if ($rights =~ m/$ac/); } return 0; } return 0; } ###################################################################### sub tablist { # $sid, $pid, \'tabsheet\', \'focus\', startN, (array of names) # создание панели с закладками (используется в page.asp и section.asp) my ($sid, $pid, $tabsheet_name, $focus_name, $start_page, @pages) = @_; my $pagenum = scalar(@pages)-1; my ($out,$focus1,$focus2); =pod =head1 Параметры вызова: tablist($sid, $pid, \'tabsheet\', \'focus\', startN, (array of names)); =item $sid, $pid Номера раздела и страницы Если номер раздела < 0 - закладка со ссылкой на дерево объектов НЕ отображается. =item \'tabsheet\' HTML Идентификатор панели с табами =item startN Номер закладки, которую нужно открыть при старте страницы Для этого в запросе должен присутствовать параметр "ctsh=N" где N - номер закладки =item \'focus\' Идентификатор HTML объекта для установки фокуса при открытии каждой из закладок =item (array of names) Список строк, являющихся текстом на закладках =head1 Пример реализации панели с табами: <style> #tabsheet0 {display:none} /* в некоторых версяиях браузеров из за ошибки надо комментировать эту строку */ #tabsheet1 {display:none} #tabsheet2 {display:none} .tabsheet { ... } </style> <#% my @tabs = ( \'<img src="/pic/page1.png"> Page One\', \'<img src="/pic/page2.png"> Page Two\', \'<img src="/pic/page3.png"> Page Three\' ); my $ctsh; $ctsh = $FORM->{ctsh}; $ctsh = $QUERY->{ctsh} if ($ctsh eq \'\'); print tablist(-1, \'\', \'tabsheet\', \'fcs\', ($ctsh =~ m/[012]/)?$ctsh:0, @tabs); %#> <div class="tabarea"> <table border="0" width="100%" cellpadding="8" cellspacing="0"><tr><td> <div id="tabsheet0" class="tabsheet">Page 1<br><input type="text" id="fcs0"></div> <div id="tabsheet1" class="tabsheet">Page 2<br><input type="text" id="fcs1"></div> <div id="tabsheet2" class="tabsheet">Page 3<br><input type="text" id="fcs2"></div> </td></tr></table> </div> =cut my $css = qq[ <style> #tablist { padding: 3px 0 3px 6px; margin-left: 0; font: 13px Tahoma; /* line-height: 16px; */ white-space: nowrap; } #tablist li { list-style: none; margin: 0; display: inline; white-space: nowrap; } #tablist li a { color: #555; padding: 3px 6px; margin-left: 3px; border: 1px solid #888; border-bottom: none; background: #ddd; text-decoration: none; font-weight: normal; border-top-left-radius: 6px; border-top-right-radius: 6px; } </style> ]; my $javascript = qq[ <script language="JavaScript"> window.onload = function(){ showTab($start_page); } function showTab(tabnum) { for (i = 0; i <= $pagenum; i++) { document.getElementById(\'$tabsheet_name\'+i).style.display = \'none\'; tln = document.getElementById(\'xtl\'+i); tln.style.color = \'#555\'; tln.style.background = \'#ddd\'; tln.style.borderBottom = \'1px solid #888\'; } var tsheet = document.getElementById(\'$tabsheet_name\'+tabnum); var fcname = document.getElementById(\'$focus_name\'+tabnum); var tln = document.getElementById(\'xtl\'+tabnum); if (tsheet) { tsheet.style.display = \'block\'; } if (fcname) { fcname.focus(); } if (tln) { tln.style.color = \'#000\'; tln.style.background = \'white\'; tln.style.borderBottom = \'1px solid white\'; tln.style.backgroundImage = \'url(/admin/pic/tab_bg.gif)\'; } } </script]; # See ...Perl\\site\\lib\\Apache\\ASP\\GlobalASA.pm, lines 91,92... $out .= $css.$javascript.">\\n"; # stupid bug... $out .= qq{\\n<ul id="tablist" style="margin-bottom:0px;">\\n}; if ($sid > 0) { # отображение закладки со ссылкой на дерево объектов $out .= qq{ <li><a href="treejx.asp?sid=$sid&pid=$pid" style="padding-left:0;margin-left:0;background-color:#20a020;color:#c0ffc0;text-decoration:none" target="treeframe">&nbsp;<acronym title="Отобразить курсор на дереве объектов"><img src="/admin/pic/tree/node-tree.png" class="trico">&nbsp;$sid/$pid&nbsp;</acronym></a></li>\\n}; } for(my $i=0; $i<=$pagenum; $i++) { $pages[0] = qq{<span style="color:blue">$pages[0]</span>} if (($section{sectype} eq \'asp\') || ($sid == 0)); $out .= qq{ <li><a href="#$i" id="xtl$i" onclick="showTab($i)">$pages[$i]</a></li>\\n}; } $out .= qq{</ul>\\n}; return $out; } ####################################################################### sub get_indexgroup_str { # (index_name) # получить строку списка разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return $idx; } ####################################################################### sub get_indexgroup_lst { # (index_name) # получить список разделов по имени my $index_name = shift; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return split(/,\\s*/, $idx); } ####################################################################### sub exist_in_indexgroup { # ($index_name, $value) # проверить наличие $value в списке разделов по имени my ($index_name, $value) = @_; my ($idx) = getonerec("select flist from srvindex where name=\'$index_name\'"); return exist_in_list($value, split(/,\\s*/, $idx)); } ###################################################################### sub recalctree { # ($sid) # получить список всех подчиненных разделов от указанного my $sl = shift; $sl =~ s/\\D+/,/g; my @srvindex = (); my ($q, $s, $r); $q = "select sid from section order by sid"; $s = $db->prepare($q) || print $db->errstr, ", query:[$q]<br>\\n"; $s->execute() || print $db->errstr, ", query:[$q]<br>\\n"; while ( $r = $s->fetchrow_hashref ) { my @tw = (); @treewalk = &tree_walk($r->{sid}); foreach my $item (reverse @treewalk) { push(@tw, $item->[0]); } my %union = (); my %isect = (); # объединение и пересечение множеств @tw и "$sl", результат в %union и %isect foreach my $e (@tw, split(\',\', $sl)) { $union{$e}++ && $isect{$e}++ } push(@srvindex, $r->{sid}) if (scalar(keys %isect)); } $s->finish; return @srvindex; } ####################################################################### sub autorecalctree { # Обновление индексных групп при изменении иерархии разделов my $visual = shift; my ($q1, $s1, $r1); my ($q2, $s2, $r2); print qq{<div id="autoupdate" style="padding-top:10px;">Обновление индексных групп : } if ($visual); $q1 = "select id,slist from srvindex order by id desc"; $s1 = $db->prepare($q1) || print $db->errstr, ", query:[$q1]<br>\\n"; $s1->execute() || print $db->errstr, ", query:[$q1]<br>\\n"; while ( $r1 = $s1->fetchrow_hashref ) { print qq{<span style="background-color:blue;color:white">&nbsp;$r1->{id}&nbsp;</span>&nbsp;} if ($visual); $Response->Flush() if ($visual); # anti timeout solution my $flist = join(\',\', recalctree($r1->{slist})); $q2 = "update srvindex set flist=? where id=$r1->{id}"; $s2 = $db->prepare($q2) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->execute($flist) || print $db->errstr, ", query:[$q2]<br>\\n"; $s2->finish; } $s1->finish; print qq{\\n</div>\\n<style>#autoupdate {display:none} </style>\\n} if ($visual); } ####################################################################### sub check_for_secdel { # (sid) # проверка возможности удаления раздела my ($sid) = @_; my @cd_msg = (); my ($cs, $cp, $cf) = (0, 0, 0); my $filedir = "$uploaddir/$sid"; # считаем количество подразделов ($cs) = getonerec("select count(sid) from section where secparent = $sid"); push(@cd_msg, "Разделов: <span style=\'color:red\'>$cs</span>") if ($cs); # считаем количество документов в разделе ($cp) = getonerec("select count(pid) from documents where sid = $sid"); push(@cd_msg, "Страниц: <span style=\'color:red\'>$cp</span>") if ($cp); # считаем количество файлов в разделе if (opendir(D, $filedir)) { my @rm_dir = readdir(D); closedir(D); $cf = scalar(@rm_dir); # уменьшаем $cf из за служебных папок: \'.\' и \'..\' foreach my $d (@rm_dir) { $cf-- if ($d =~ m/^\\.+$/); } } push(@cd_msg, "Файлов: <span style=\'color:red\'>$cf</span>") if ($cf); return @cd_msg; } ###################################################################### sub get_section { # (sid) # прочитать информацию о разделе # return hash my ($sid) = @_; my (%ret, $query, $st, $row) = (); if ($sid > 0) { $query = "select * from section where sid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } $st->finish; } return %ret; } ###################################################################### sub get_document { # (sid, pid) # прочитать документ # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); $query = "select * from documents where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; $row = $st->fetchrow_hashref; $st->finish; foreach my $i (keys %{$row}) { $ret{$i} = $row->{$i}; } return %ret; } ###################################################################### sub get_document_ex { # (sid, pid) # прочитать документ с расширенными полями # return hash my ($sid, $pid) = @_; my (%ret, $query, $st, $row) = (); %ret = get_document($sid, $pid); $query = "select field,value from documents_ex where sid=? and pid=?"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { $ret{$row->{field}} = $row->{value}; } $st->finish; return %ret; } ###################################################################### sub get_sec_documents { # (sid, \'body\') # прочитать все документы раздела (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body) = @_; my (@ret, $query, $st, $row, $b) = (); $b = \'pagebody,\' if ($body); my $fields = "sid,pid,userid,url,pagename,".$b."pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus"; $query = "select $fields from documents where sid=? order by pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid) || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; return @ret; } ###################################################################### sub get_sec_documents_ex { # (sid, body, x_where) # прочитать все документы раздела с расширенными полями (с или без тела документа) # return array of hashes # body == [ 1,0 ] my ($sid, $body, $x_where) = @_; my (@ret, @ret_ex, $query, $st, $row, $b) = (); $b = \'documents.pagebody,\' if ($body); my $fields = " documents.sid, documents.pid, documents.userid, documents.url, documents.pagename, $b documents.pagedate, documents.pagemodify, documents.pageorder, documents.sh_hdr, documents.sh_dir, documents.sh_nav, documents.sh_tab, documents.docstatus, documents_ex.field, documents_ex.value"; $query = "select $fields from documents left outer join documents_ex on (documents_ex.sid = documents.sid) and (documents_ex.pid = documents.pid) where documents.sid = $sid"; $query = "$query and ($x_where)" if ($x_where); # open(F, ">>$site_path/asa/q.log"); # print F "get_sec_documents_ex: $query\\n\\n"; # close(F); $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute() || print $db->errstr,", Q:[$query]\\n"; while ( $row = $st->fetchrow_hashref ) { push(@ret, $row); } $st->finish; # получили массив @ret с дублями строк для полей из documents my %h = (); foreach my $i (@ret) { # чтобы избавится от дублей пихаем строки в хэш, где ключ = \'sid.pid\' if (!defined($h{"$i->{sid}.$i->{pid}"})) { $h{"$i->{sid}.$i->{pid}"} = { \'sid\' => $i->{\'sid\'}, \'pid\' => $i->{\'pid\'}, \'userid\' => $i->{\'userid\'}, \'url\' => $i->{\'url\'}, \'pagename\' => $i->{\'pagename\'}, \'pagedate\' => $i->{\'pagedate\'}, \'pagemodify\' => $i->{\'pagemodify\'}, \'pageorder\' => $i->{\'pageorder\'}, \'sh_hdr\' => $i->{\'sh_hdr\'}, \'sh_dir\' => $i->{\'sh_dir\'}, \'sh_nav\' => $i->{\'sh_nav\'}, \'sh_tab\' => $i->{\'sh_tab\'}, \'docstatus\' => $i->{\'docstatus\'}, $i->{\'field\'} => $i->{\'value\'}, }; } else { # в случае сущесвования такой же строки в хэше - добавляем очередное поле из documents_ex $h{"$i->{sid}.$i->{pid}"}->{$i->{\'field\'}} = $i->{\'value\'}; } } @ret = (); # перекидываем всё из хэша в массив foreach my $i (keys %h) { push(@ret, $h{$i}); } return @ret; } ###################################################################### sub create_document { # (sid, userid, hash_fields) # создать документ в указанном разделе my ($sid, $userid, %fields) = @_; my ($pid, $query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # search new $pid for $sid my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $pid++; # set default values for new document $fields{pageorder} = $pid * 10; # insert new fields of document $query = "insert into documents (sid,pid,userid,url,pagename,pagebody,pagedate,pagemodify,pageorder,sh_hdr,sh_dir,sh_nav,sh_tab,docstatus) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'create_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_document_ex { # (sid, userid, hash_fields) # создать документ с расширенными полями в указанном разделе my ($sid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { create_document($sid, $userid, %fields); my ($pid) = getonerec("select max(pid) from documents where sid=$sid"); $fields{pagebody} = \'\'; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'create_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document { # ($sid, $pid, $userid) # удалить документ my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_document_ex { # ($sid, $pid, $userid) # удалить документ с расширенными полями my ($sid, $pid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my %fields = get_document($sid, $pid); $query = "delete from documents where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; journaldata(\'delete_document\', $sid, $pid, $userid, %fields); logdata($query); my %fields_ex = get_document_ex($sid, $pid); $query = "delete from documents_ex where sid=$sid and pid=$pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = \'\'; foreach my $i (keys %fields_ex) { $fields{pagebody} .= "EX:[$i]: $fields_ex{$i}<br>\\n"; } journaldata(\'delete_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub delete_section { # (sid) # удалить раздел my ($sid) = @_; my ($st, $query); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { $query = "delete from section where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); # remove rights for deleted section $query = "delete from usersacc where sid = $sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document { # (sid, pid, userid, hash_fields) # заменить документ my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { # update fields of document $query = "update documents set userid=?,url=?,pagename=?,pagebody=?,pagedate=?,pagemodify=?,pageorder=?,sh_hdr=?,sh_dir=?,sh_nav=?,sh_tab=?,docstatus=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{pagemodify}, $fields{pageorder}, $fields{sh_hdr}, $fields{sh_dir}, $fields{sh_nav}, $fields{sh_tab}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; journaldata(\'replace_document\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub replace_document_ex { # (sid, pid, userid, hash_fields) # заменить документ с расширенными полями my ($sid, $pid, $userid, %fields) = @_; my ($query, $st) = (); my (%fields_ex) = (); # separate fields to %fields and \'_ex\' to %fields_ex foreach my $i (keys %fields) { if (!exist_in_list($i, @doc_fields)) { $fields_ex{$i} = $fields{$i}; delete($fields{$i}); } } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { replace_document($sid, $pid, $userid, %fields); $fields{pagebody} = \'\'; # delete \'_ex\' fields in documents_ex $query = "delete from documents_ex where sid = $sid and pid = $pid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # insert \'_ex\' fields to documents_ex $query = "insert into documents_ex (sid,pid,field,value) values (?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; foreach my $i (keys %fields_ex) { $st->execute($sid, $pid, $i, $fields_ex{$i}); $fields{pagebody} .= "EX:[$i]== $fields_ex{$i}\\n"; } journaldata(\'replace_document_ex\', $sid, $pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub create_section { # (hash_fields) # создать раздел my (%fields) = @_; my ($st, $sid, $query); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($secorder) = getonerec("select max(secorder) from section where secparent=$FORM->{secparent}"); $secorder = $secorder + 10; $fields{sectype} = $fields{sectype} || \'table\'; $fields{sorttype} = $fields{sorttype} || \'az\'; # insert record of section $query = "insert into section (secparent,secname,secdescr,sectype,plug_view,plug_admn,plug_ico,startpage,sorttype,secorder,sh_nav,sh_dir,sh_hdr) values (?,?,?,?,?,?,?,?,?,?,?,?,?)"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secparent}, $fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, ($fields{sectype} eq \'table\') ? $fields{startpage} : 0, $fields{sorttype}, $secorder, ($fields{sh_nav} eq "on") ? "Y" : "N", ($fields{sh_dir} eq "on") ? "Y" : "N", ($fields{sh_hdr} eq "on") ? "Y" : "N", ) || print $db->errstr, ", query:[$query]<br>\\n"; $sid = $db->{\'mysql_insertid\'}; logdata($query); # delete all rights for new section $query = "delete from usersacc where sid=$sid"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; # copy rights from parent to current section $query = "insert into usersacc (userid,sid,rights) select userid,$sid,rights from usersacc where sid=$FORM->{secparent}"; $db->do($query) || print $db->errstr, ", query:[$query]<br>\\n"; $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return $sid; } ###################################################################### sub update_section { # (sid, hash_fields) # изменить раздел my ($sid, %fields) = @_; my ($st, $query); $fields{secparent} = 0 if (!defined($fields{secparent})); return -1 if (!$fields{secname}); return -2 if ($fields{secparent} !~ m/^\\d+$/); return -3 if ($fields{sectype} !~ m/table|asp/); return -4 if (($fields{sectype} eq \'asp\') && ($fields{plug_view} eq \'\')); return -5 if (($fields{sectype} eq \'table\') && ($fields{startpage} !~ m/^\\-*\\d+$/)); return -6 if ($fields{secorder} !~ m/^\\d+$/); $fields{sorttype} = $fields{sorttype} || \'az\'; $fields{sh_nav} = ($fields{sh_nav} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_dir} = ($fields{sh_dir} =~ m/on|Y/) ? \'Y\' : \'N\'; $fields{sh_hdr} = ($fields{sh_hdr} =~ m/on|Y/) ? \'Y\' : \'N\'; if ($fields{sectype} eq \'table\') { $fields{plug_view} = \'\'; $fields{plug_admn} = \'\'; $fields{plug_ico} = \'\'; } elsif ($fields{sectype} eq \'asp\') { $fields{startpage} = 0; } my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { if ($godaccess) { # only GODS may change fields: \'plug_view, plug_admn, plug_ico, sec_tpl\' $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, plug_view=?, plug_admn=?, plug_ico=?, sectpl=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{plug_view}, $fields{plug_admn}, $fields{plug_ico}, $fields{template}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } else { $query = "update section set secname=?, secdescr=?, secparent=?, sectype=?, startpage=?, sorttype=?, secorder=?, sh_nav=?, sh_dir=?, sh_hdr=? where sid=$sid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($fields{secname}, ($fields{secdescr}) ? $fields{secdescr} : $fields{secname}, $fields{secparent}, $fields{sectype}, $fields{startpage}, $fields{sorttype}, $fields{secorder}, $fields{sh_nav}, $fields{sh_dir}, $fields{sh_hdr}) || print $db->errstr, ", query:[$query]<br>\\n"; } logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub move_document { # ($sid, $pid, $new_sid, $userid) # переместить документ в другой раздел my ($sid, $pid, $new_sid, $userid) = @_; my ($query, $st) = (); my $in_trn = 0; $in_trn = 1 if (!$db->{AutoCommit}); $db->{AutoCommit} = 0 if (!$in_trn); eval { my ($new_pid, $new_pageorder) = getonerec("select max(pid),max(pageorder) from documents where sid=$new_sid"); $new_pid++; $new_pageorder = $new_pageorder + 10; my %fields = get_document($sid, $pid); $query = "update documents set userid=?, sid=?, pid=?, pageorder=? where sid=$sid and pid=$pid"; $st = $db->prepare($query) || print $db->errstr, ", query:[$query]<br>\\n"; $st->execute($userid, $new_sid, $new_pid, $new_pageorder) || print $db->errstr, ", query:[$query]<br>\\n"; $fields{pagebody} = "Change: <b>$sid/$pid</b> to <b>$new_sid/$new_pid</b>"; journaldata(\'move_document\', $new_sid, $new_pid, $userid, %fields); logdata($query); $db->commit if (!$in_trn); }; $db->{AutoCommit} = 1 if (!$in_trn); return 0; } ###################################################################### sub journaldata { # ($func, $sid, $pid, $userid, %fields) # записать в журнал документ/раздел/сообщение my ($func, $sid, $pid, $userid, %fields) = @_; my $query = "insert into journal (ipaddr,function,sid,pid,userid,url,pagename,pagebody,pagedate,docstatus) values (?,?,?,?,?,?,?,?,?,?)"; my $st = $db->prepare($query) || print $db->errstr,", Q:[$query]\\n"; $st->execute($remoteaddr, $func, $sid, $pid, $userid, $fields{url}, $fields{pagename}, $fields{pagebody}, $fields{pagedate}, $fields{docstatus} ) || print $db->errstr,", Q:[$query]\\n"; } ###################################################################### sub cutwords { # ($string, $numwords) # отрезать от новостного сообщения начало в $numwords слов my ($str, $nw) = @_; my $ret; $str =~ s!<p(.*?)>! <p$1>!i; $str =~ s!<br>! <br>!i; $str =~ s!<div(.*?)>! <div$1>!i; $str =~ s!<(/*strong)>!%%$1%%!gi; $str =~ s!<(/*)b>!%%$1strong%%!gi; $str =~ s!<img (.+?)>!%%img $1%%!i; $str =~ s/(<(?=!--)([^>]|\\n)*--(?=>)>)//ig; $str =~ s/|(<\\/?([^>]|\\n)*>)//g; $str =~ s/&nbsp;/ /g; $str =~ s/\\s+/ /g; $str =~ s!%%(/*strong)%%!<$1>!gi; $str =~ s!%%img (.+?)%%!<img $1>!i; my @a = split(/\\s/, $str); if ($#a > $nw) { $ret = join(\' \', splice(@a, 0, $nw)) . qq{<b> . . .</b>}; } else { $ret = $str; } if (($ret =~ m!<strong>!) && ($ret !~ m!</strong>!)) { $ret .= "</strong>"; } return $ret; } ###################################################################### sub round { # округлить значение my $i = shift; return $i - int($i) < 0.5 ? int($i) : int($i)+1; } ###################################################################### sub rss_expand_img_url { # разворачивает URL картинки для RSS my ($u1, $u2, $u3) = @_; return "<img $u1"."src=\\"http://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_expand_hrf_url { # разворачивает URL ссылки для RSS my ($u1, $u2, $u3) = @_; return "<a $u1"."href=\\"https://$servername"."$u2\\"$u3>" if ($u2 !~ m!http://!); return ""; } ###################################################################### sub rss_clear_html_to_xml { # причесывает страницу по правилам XML my $txt = shift; $txt =~ s/<img (.*?)src="(.+?)"(.*?)>/rss_expand_img_url($1,$2,$3)/ige; $txt =~ s/<a (.*?)href="(.+?)"(.*?)>/rss_expand_hrf_url($1,$2,$3)/ige; $txt =~ s/&nbsp;/ /g; $txt =~ s/\\s+/ /g; $txt =~ s/&/&amp;/g; $txt =~ s/</&lt;/gi; return $txt; } ###################################################################### sub get_root_category { # для текущего раздела (что в последнем элементе массива @treewalk) ищет предка, у которого родитель = 4 if (@treewalk) { if (@treewalk[scalar(@treewalk)-1]->[0] == 4) { return @treewalk[scalar(@treewalk)-2]->[1]; } else { return @treewalk[scalar(@treewalk)-1]->[1]; } } else { return ""; } } ###################################################################### sub send_mail_smtp { # ($host, $from, $to, $body) my ($_host, $_from, $_to, $_xbody) = @_; $_xbody = "To: $_to\\n$_xbody"; my $smtp = Net::SMTP->new($_host, Hello => \'mail.arhcity.ru\', Timeout => 30); $smtp->mail($_from); $smtp->to($_to); $smtp->data(); $smtp->datasend($_xbody); $smtp->dataend(); $smtp->quit; } ###################################################################### sub get_cookie { # возвращает значение куки по ключу (см. \\asp\\admin\\lib\\adminlib.js) my $name = shift; my $cook = $SERVER->{HTTP_COOKIE}; my @arr = split(/;\\s*/, $cook); my %ck = (); foreach my $c (@arr) { my ($k, $v) = split(/=/, $c); $ck{$k} = $v; } return $ck{$name}; } ###################################################################### sub random_str { # возвращает строку указанной длинны (или 5) из случайных символов my $len = shift || 5; my $c = \'0123456789abcdefghijklmnopqrstuvwxyz\'; my $l = length($c); my $s = \'\'; for (1 .. $len) { $s .= substr($c, int(rand()*$l), 1); } return $s; } ###################################################################### sub check_body_style { # ( body ) my $body = shift; my (@cb_arr, @ret_txt) = (); @cb_arr = (); @cb_arr = $body =~ m!<(img|a).* (src|href)="data:image/(gif|png|jpeg);base64,(\\S+)"!sg; push(@ret_txt, "&bull; Недопустимое применение ссылок формата \\"data:image\\" (".(scalar(@cb_arr)/4)." раз.)") if (@cb_arr > 0); @cb_arr = (); @cb_arr = $body =~ m/<w:LsdException/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'LsdException\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/<w:WordDocument>/sg; push(@ret_txt, "&bull; В тексте присутствует таблица стилей \'WordDocument\'") if (@cb_arr > 1); @cb_arr = (); @cb_arr = $body =~ m/text-indent:27\\.0pt|class="MsoNormal"|tab-stops:list -9\\.0pt|mso-layout-grid-align:/sg; push(@ret_txt, "&bull; В тексте присутствуют инлайн-стили от Microsoft Word (".scalar(@cb_arr)." раз.)") if (@cb_arr > 4); @cb_arr = (); @cb_arr = $body =~ m/style="font-family: \'Times New Roman\'/sg; push(@ret_txt, "&bull; Слишком частое использование шрифта \'Times New Roman\' (".scalar(@cb_arr)." раз.)") if (@cb_arr > 5); @cb_arr = (); @cb_arr = $body =~ m/<span style="color: .+?;">|<span style="background-color: rgb(255, 255, 255);">/sg; push(@ret_txt, "&bull; Частое/неуместное использование цветового выделения (".scalar(@cb_arr)." раз.)") if (@cb_arr > 8); if (@ret_txt) { return join("<br>\\n", @ret_txt); } else { return 0; } } ###################################################################### sub meta_og_tags { # возвращает "Open Graph" тэги для страницы my ($sid, $pid) = @_; my $pageheader = $section{secname}; $pageheader = "Городские новости" if ($sid == 0); # https://ruogp.me/ - Протокол Open Graph my $r = \'\'; $r .= qq{<meta property="og:site_name" content="Администрация города Архангельска" />\\n}; $r .= qq{<meta property="og:url" content="http://arhcity.ru/?page=$sid/$pid" />\\n}; $r .= qq{<meta property="og:title" content="$pageheader" />\\n}; $r .= qq{<meta property="og:description" content="$document{pagename}" />\\n}; $r .= qq{<meta property="og:image" content="http://arhcity.ru/pic/og-image-arhcity.jpg" />\\n}; if ($section{sectype} eq \'table\') { my $_r = \'\'; my $c = 0; my @og_image = $document{pagebody} =~ m!<img src="(.+?)" .+/>!g; foreach my $i (@og_image) { $i =~ s!http://.+?\\.ru!!g; $_r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; $c++; } if ($c > 5) { # если картинок на странице много ( >5 ) - показываем только первую my $i = @og_image[0]; $i =~ s!http://.+?\\.ru!!g; $r .= qq{<meta property="og:image" content="http://arhcity.ru$i" />\\n}; } else { $r = $_r; } } return $r; } ###################################################################### sub gen_int_EO { # (number) # возвращает случайное чётное/нечётное число в интервале 0..number в зависимости от чётности number my $n = shift; my $r = int(rand() * $n); if ($n % 2 == 0) { $r++ if ($r % 2 == 1); } else { $r++ if ($r % 2 == 0); } return $r; } ###################################################################### sub update_msie_css { # внедряем в default.css значения переменных из colors.css и создаём default-ie.css my $ret = 0; my %vars = (); my $default_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default.css"; my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; my $default_ie_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/default-ie.css"; my ($t_default_css) = (stat($default_css_fn))[9]; my ($t_colors_css) = (stat($colors_css_fn))[9]; my ($t_default_ie_css) = (stat($default_ie_css_fn))[9]; if (($t_default_css > $t_default_ie_css) || ($t_colors_css > $t_default_ie_css)) { open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = <FC>) { $vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); open(FS, "< $default_css_fn") || die "Can\'t open $default_css_fn, $!\\n"; open(FO, "> $default_ie_css_fn") || die "Can\'t open $default_ie_css_fn, $!\\n"; while (my $l = <FS>) { next if ($l =~ m/colors.css/); $l =~ s/(var\\((--.+?)\\))/exists($vars{$2})?$vars{$2}:\'none\'/gsex; print FO $l; } close(FO); close(FS); } $ret = 1 if ((stat($default_ie_css_fn))[7] > 0); # if filesize $default_ie_css_fn > 0 - file OK. return $ret; } ###################################################################### ## XML subroutines ################################################### ###################################################################### # see http://www.arhcity.ru/1.asp # ###################################################################### sub ipcms::button { my ($args, $html) = @_; my ($ico, $spacer); if (( $args->{ico}) && ( $args->{txt})) { $spacer = \'&nbsp;\'; } if ((!$args->{ico}) && ( $args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="1" height="16">\'; } if (( $args->{ico}) && (!$args->{txt})) { $spacer = \'\'; } if ((!$args->{ico}) && (!$args->{txt})) { $spacer = \'<img src="/pic/_t.gif" width="16" height="16">\'; } if ($args->{ico}) { $ico = qq{<img src="$args->{ico}" width="16" height="16">}; } print qq{<a href="$args->{url}"><div class="shbutton">}.$ico.$spacer.$args->{txt}.qq{</div></a>}; } ###################################################################### sub ipcms::panel { my ($args, $html) = @_; my ($o_style, $style); $o_style = $args->{style} if ($args->{style}); $style = qq{ style="$o_style"} if ($o_style); print qq{<div class="border_area"$style>$html<br>}; print_dump($args); print qq{</div>\\n}; } ;; sub exit { $main::Response->End(); } ;; no lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; 1;' called at /usr/local/share/perl5/Apache/ASP/GlobalASA.pm line 122 Apache::ASP::GlobalASA::new('Apache::ASP=HASH(0x562e3465c280)') called at /usr/local/share/perl5/Apache/ASP.pm line 389 Apache::ASP::new('Apache::ASP', 'Apache2::RequestRec=SCALAR(0x562e342fd2a8)', '/var/www/HDD2/mc.arhcity.ru/asp/index.asp') called at /usr/local/share/perl5/Apache/ASP.pm line 184 Apache::ASP::handler('Apache2::RequestRec=SCALAR(0x562e342fd2a8)') called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 eval {...} called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 , /usr/local/share/perl5/Apache/ASP.pm line 1722
Debug Output
  1. errors compiling global.asa: Errno architecture (x86_64-linux-thread-multi-3.10.0-957.1.3.el7.x86_64) does not match executable architecture (x86_64-linux-thread-multi-3.10.0-693.17.1.el7.x86_64) at /usr/lib64/perl5/Errno.pm line 11. at /usr/lib64/perl5/Errno.pm line 11. require Errno.pm called at /usr/lib64/perl5/IO/Socket.pm line 18 IO::Socket::BEGIN() called at /usr/lib64/perl5/Errno.pm line 0 eval {...} called at /usr/lib64/perl5/Errno.pm line 0 require IO/Socket.pm called at /usr/share/perl5/Net/SMTP.pm line 15 Net::SMTP::BEGIN() called at /usr/lib64/perl5/Errno.pm line 0 eval {...} called at /usr/lib64/perl5/Errno.pm line 0 require Net/SMTP.pm called at /var/www/HDD2/mc.arhcity.ru/asa/global.asa line 12 Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax::BEGIN() called at /usr/lib64/perl5/Errno.pm line 0 eval {...} called at /usr/lib64/perl5/Errno.pm line 0 eval ' #line 1 /var/www/HDD2/mc.arhcity.ru/asa/global.asa package Apache::ASP::Compiles::__ASP__var_www_HDD2_mc_arhcity_ru_asax; ;; use strict ;; use vars qw($Application $Session $Response $Server $Request); ;; use lib qw(/var/www/HDD2/mc.arhcity.ru/asa); ;; #!/usr/bin/perl use Time::HiRes qw(gettimeofday tv_interval); use Apache::DBI; # automatic persistent database connections use DBI; use HTTP::Date; use Digest::SHA1 qw(sha1_hex sha1_base64); use Socket; use URI::UTF8::Punycode; use APR::UUID; use Text::Iconv; use Net::SMTP; # when PerlSetVar UseStrict setting on, need to declare # global variables with "use vars" ################################################################## # declare global variables use vars (\'$db\', # database interface \'$FORM\', # form data, method POST \'$QUERY\', # form data, method GET \'$POST\', # unformat form data, method POST \'$SERVER\', # server variables \'$localnet\', # access from local network \'$have_inet\', # access to internet \'$remoteaddr\', # remote IP address \'$useragent\', # UserAgent () \'$site_admin\', # Enable extra functions for site admins \'$logged_in\', # admin access by session \'$lc_logged_in\', # private cabinet access by session \'$servername\', # name of server \'$addrubrics\', # additional menu "rubrics" \'$tpl_dir\', # html template directory \'$godaccess\', # GOD access \'$hires_time\', # time generation of page ############################# \'%userinfo\', # entrie user data (hash) \'%section\', # entrie section data (hash) \'%document\', # entrie document data (hash) ############################# \'@treewalk\', # walking from leaf to root = ([$node, $secname, $sectpl]) \'%mod_params\', # parameters for plugins \'$zx_counter\', # counter for all unique repitable operations \'$site_url\', # url to site \'$site_path\', # path to site location \'$blindview\', # blind vew mode \'%CSS_vars\', # CSS variables ); ################################################################## my $host = \'localhost\'; my $db_name = \'ipcms3\'; my $dsn = "DBI:mysql:database=$db_name:host=$host"; my $username = \'root\'; my $password = \'\'; ################################################################## my $log_file; my $uploaddir; my $admin_dir = "/admin/"; my $lcab = "/lc/"; # list of datastore fields for separate \'_ex\' and non \'_ex\' fields my @doc_fields = qw(sid pid userid url pagename pagebody pagedate pagemodify pageorder sh_hdr sh_dir sh_nav sh_tab docstatus rating1 rating2); # at the begining of the page execution sub Script_OnStart { $hires_time = [gettimeofday]; $Response->Include("site_setup.asp"); # get default values for current site $log_file = "$site_path/datafiles/ipcms3.log"; $uploaddir = "$site_path/asp/data"; $Response->{\'ContentType\'} = "text/html"; $Response->{\'Charset\'} = "Windows-1251"; # $Response->{\'Expires\'} = 0; # page expired after NN seconds from download. # $Response->{\'Last-Modified:\'} = time2str(time-1); $FORM = $Request->Form(); $QUERY = $Request->QueryString(); # $POST = $Request->BinaryRead($Request->ServerVariables(\'CONTENT_LENGTH\')); # for debug $SERVER = $Request->ServerVariables(); $remoteaddr = $SERVER->{\'REMOTE_ADDR\'}; $servername = $SERVER->{\'SERVER_NAME\'}; $tpl_dir = $SERVER->{\'DOCUMENT_ROOT\'}."/templates"; $blindview = get_cookie("blindview") || 0; %userinfo = (); %section = (); %document = (); $addrubrics = \'\'; $site_admin = 0; $logged_in = 0; $godaccess = 0; $localnet = 0; $have_inet = 0; @treewalk = (); $zx_counter = 0; # Global Redirect Block... if ($servername eq \'arhcity.ru\') { $Response->Redirect("http://$site_url"); } if ($servername eq \'arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } if ($servername eq \'www.arhirc.ru\') { $Response->Redirect("http://$site_url/?page=2331/0"); } # if ($SERVER->{HTTPS} ne \'on\') { # $Response->Redirect("https://www.arhcity.ru/?$SERVER->{QUERY_STRING}"); # } my $ic = Text::Iconv->new("UTF-8", "WINDOWS-1251"); my @r = (); foreach my $i (split(/\\./, $servername)) { if ($i =~ m/^xn--/) { push(@r, puny_dec($i)); } else { push(@r, $i); } } $servername = join(\'.\', @r); $servername = $ic->convert($servername); if ($SERVER->{HTTP_USER_AGENT} =~ m/edge/i) { $useragent = \'edge\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/chrome/i) { $useragent = \'chrome\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/webkit/i) { $useragent = \'safari\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/opera/i) { $useragent = \'opera\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/msie/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/trident/i) { $useragent = \'msie\'; } elsif ($SERVER->{HTTP_USER_AGENT} =~ m/mozilla/i) { $useragent = \'mozilla\' } else { $useragent = \'unknown\'; } if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { # read CSS color variables for replace in html code (MSIE/Edge not support CSS vars); my $colors_css_fn = "$SERVER->{DOCUMENT_ROOT}/templates/colors.css"; open(FC, "< $colors_css_fn") || die "Can\'t open $colors_css_fn, $!\\n"; while (my $l = ) { $CSS_vars{$1} = $2 if ($l =~ m/(--.+?):\\s*(.+);/); } close(FC); } if (($remoteaddr =~ m/^192\\.168\\./) || ($remoteaddr eq \'212.14.176.38\') || ($remoteaddr eq \'212.14.176.39\') || ($remoteaddr eq \'212.14.176.46\') || ($remoteaddr eq \'212.14.176.40\') || ($remoteaddr eq \'212.14.176.41\') || ($remoteaddr eq \'212.14.176.44\') || ($remoteaddr eq \'195.239.119.234\') # Городской центр гражданской защиты ) { $localnet = 1; } if (($localnet) && ( # Enable extra functions for site admins ($remoteaddr eq \'192.168.1.84\') || # GaidukAV ($remoteaddr eq \'192.168.1.44\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.45\' ) || # KorzhevDP ($remoteaddr eq \'192.168.1.46\' ) || # KorzhevDP ($remoteaddr eq \'192.168.51.144\') || # VishnyakovNS ($remoteaddr eq \'192.168.1.102\') || # EkimovKS v.1 ($remoteaddr eq \'192.168.1.110\') || # EkimovKS v.2 ($remoteaddr eq \'192.168.51.42\')) # EkimovKS v.3 ) { $site_admin = 1; } # connect to database $db = DBI->connect($dsn, $username, $password); if (! $db) { print "

    Database server not responding.
    Try later.

    \\n"; $Response->End(); } # ONLY FOR RUSSIAN for MySQL !!! $db->do("set names cp1251"); if ($localnet) { # enable/disable outside scripts on site for local users without inet. ($have_inet) = getonerec("select count(ip) from squid_list where ip = \'$remoteaddr\'"); } else { $have_inet = 1; } # ------------------------------------------------------------ # $have_inet = 0; # !!! disable external scripts on site !!! # ------------------------------------------------------------ if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # !!! admin mode !!! $logged_in = 0; my $uname = $Session->{Authentication}; my $topframe = 0; if ($uname) { # logged in $logged_in = 1; $Session->{top_frame} = 0; my $adm_lib = $admin_dir . "lib/"; if ($SERVER->{\'REQUEST_URI\'} =~ m/$adm_lib/) { # read user info %userinfo = get_user_info($uname); $godaccess = 1 if ($userinfo{god} eq \'Y\'); if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no header } else { $Response->Include("page_admin_header.asp"); print qq{\\n\\n}; } if ($SERVER->{\'REQUEST_URI\'} =~ m/(section.asp)|(page.asp)|(journal.asp)|(admin.asp)/i) { $Response->Include("page_autologoff.asp"); } } } else { # not logged in $topframe = $Session->{top_frame}; if (!$topframe) { my $location = "top.location.href=\'/admin/?t=".time()."\'"; print qq{}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n\\n\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "
    ",Dumper(@_),"
    \\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n\\n\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "
    ",Dumper(@_),"
    \\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n\\n\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "
    ",Dumper(@_),"
    \\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n\\n\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "
    ",Dumper(@_),"
    \\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n\\n\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "
    ",Dumper(@_),"
    \\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n\\n\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "
    ",Dumper(@_),"
    \\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n}; $Session->{top_frame} = 1; $Response->End(); } $Response->Include("page_admin_header.asp"); print qq{\\n\\n}; $Response->Include("auth.asp", $admin_dir."index.asp"); $Response->Include("page_autologoff.asp"); $Response->End() if (! $logged_in); } } else { # !!! default access mode !!! } } # after the end of the page execution sub Script_OnEnd { if ($SERVER->{\'REQUEST_URI\'} =~ m/$admin_dir/) { # admin mode if ($SERVER->{\'REQUEST_URI\'} =~ m/(ajax)|(requestor)\\.asp/i) { # no footer } else { print qq{\\n\\n\\n}; } } else { # user mode } # \'closing\' database connection (*) see \'Persistant Connection\' $db = undef; } ###################################################################### # before flushing buffer to the web client sub Script_OnFlush { # if data is \'text/html\' ... if ($Response->{ContentType} eq \'text/html\') { # if browser not support CSS Vars - (MSIE/Edge) if (($useragent eq \'msie\') || ($useragent eq \'edge\')) { my $ref = $Response->{BinaryRef}; # using content as $$ref # parsing html files with definitions: insert CSS Vars into styles $$ref =~ s/(var\\((--.+?)\\))/exists($CSS_vars{$2})?$CSS_vars{$2}:\'none\'/gsex; } } } ###################################################################### # User Subroutines ################################################### ###################################################################### ###################################################################### sub empty_page { # Заполнить структуру для пустой страницы с пояснениями взамен НЕ найденой my ($sid, $pid) = @_; $section{sh_hdr} = \'Y\'; $document{sh_hdr} = \'Y\'; $document{sh_dir} = \'N\'; $document{sh_nav} = \'N\'; $document{pagedate} = utime2my(time()); $document{pagebody} = ${$Response->TrapInclude("page_empty_page.asp", $sid, $pid)}; } ###################################################################### sub print_dump { # Сделать дамп переменной use Data::Dumper; print "
    ",Dumper(@_),"
    \\n"; } ###################################################################### sub error { # Показать сообщение об ошибке в режиме администрирования my $msg = shift; return ${$Response->TrapInclude("page_error.asp", $msg)}; } ####################################################################### sub logdata { # ($message) # Записать в лог-файл сообщение my $message = shift; open(LOG, ">>$log_file") || die "Can\'t write LOG ($log_file), $!\\n"; print LOG udate_to_string(time)." - $remoteaddr - $userinfo{username} - $SERVER->{\'SCRIPT_NAME\'} - $message\\n"; close(LOG); } ####################################################################### sub custom_log { # ($message) # Записать в отдельный лог-файл сообщение my $message = shift; open(LOG, ">>$site_path/datafiles/custom.log") || die "Can\'t write LOG (custom.log), $!\\n"; print LOG udate_to_string(time)." $remoteaddr $userinfo{username} - $message\\n"; close(LOG); } ###################################################################### sub udate_to_string { # ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени my $unixtime = shift; my $dchar = shift || ""; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; my $r = sprintf("%02d.%02d.%04d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%02d.%02d.%04d",$mday,$mon,$year); } if ($dchar eq "t") { $r = sprintf("%02d:%02d:%02d",$hour,$min,$sec); } return $r; } ###################################################################### sub udate_to_rus_string {# ($unixtime, $dchar) # преобразовать UNIXTIME в формат даты и/или времени с русскими названиями my $unixtime = shift; my $dchar = shift || ""; my @W = qw(воскресенье понедельник вторник среда четверг пятница суббота); my @M = qw(января февраля марта апреля мая июня июля августа сентября октября ноября декабря); my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($unixtime); $year += 1900; my $r = sprintf("%d %s %04d г. %s, %02d:%02d:%02d",$mday,$M[$mon],$year, $W[$wday], $hour,$min,$sec); if ($dchar eq "d") { $r = sprintf("%d %s %04d г. %s",$mday,$M[$mon],$year,$W[$wday]); } return $r; } ###################################################################### sub datetime2utime { # ($date) # in dd.mm.yyyy hh:mm:ss # преобразовать формат даты и времени в UNIXTIME my $xdate = shift; $xdate =~ s/(\\d+)\\.(\\d+)\\.(\\d+)\\s(\\d+):(\\d+):(\\d+)/$3-$2-$1 $4:$5:$6/; return str2time($xdate); } ###################################################################### sub my2date { # преобразовать формат даты MySQL в нормальную дату return sprintf("%02d.%02d.%04d", $3,$2,$1) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)/); return ""; } ###################################################################### sub my2datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время return sprintf("%02d.%02d.%04d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)-(\\d+)-(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub date2my { # преобразовать нормальную дату формат даты MySQL return sprintf("%04d-%02d-%02d", $3,$2,$1) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/); return ""; } ###################################################################### sub datetime2my { # преобразовать нормальную дату и время в формат даты и времени MySQL return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $3,$2,$1,$4,$5,$6) if ($_[0] =~ m/(\\d+)\\.(\\d+)\\.(\\d+)\\s+(\\d+):(\\d+):(\\d+)/); return ""; } ###################################################################### sub utime2my { # преобразовать UNIXTIME в формат даты и времени MySQL my $unixtime = shift; my ($sec,$min,$hour,$mday,$mon,$year) = localtime($unixtime); $mon++; $year += 1900; return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); } ###################################################################### sub my2rus_datetime { # преобразовать формат даты и времени MySQL в нормальную дату и время с русскими названиями my $mydt = shift; my $dchar = shift; return udate_to_rus_string(str2time($mydt), $dchar); } ###################################################################### sub exist_in_list { # ($value, @list) # проверить существование значения $val в списке @list my ($val, @list) = @_; foreach my $v (@list) { return 1 if ($val eq $v); } return 0; } ###################################################################### sub uri_remove_key { # ($query_string, $key) # удаляет из HTTP строки запроса указанный ключ со значением my $x_uri = shift; my $x_key = shift; my @r_uri = (); my @x_pairs = $x_uri =~ m!^([\\?\\/]*)(\\S+)$!; $x_uri = $x_pairs[1]; my @a_uri = split(/&/, $x_uri); foreach my $p (@a_uri) { my ($k, $v) = split(/=/, $p); push(@r_uri, $p) if (!(lc($k) eq lc($x_key))); } $x_uri = \'/\'; $x_uri = $x_pairs[0] . join(\'&\', @r_uri) if (@r_uri); return $x_uri; } ###################################################################### sub js_redirect { # (url, frame) # сделать редирект средствами javascript my ($url, $frame) = @_; my $location = qq{location.href="$url";}; $location = qq{window.parent.frames[\'$frame\'].location.href=\'$url\';} if ($frame); print "\\n