1
core.php in web – MultiMag

source: web/core.php @ b490b46

Last change on this file since b490b46 was b490b46, checked in by Blacklight <blacklight@…>, 8 years ago
  • Слияние с веткой mysqli
  • Property mode set to 100644
File size: 39.0 KB
Line 
1<?php
2//      MultiMag v0.1 - Complex sales system
3//
4//      Copyright (C) 2005-2013, BlackLight, TND Team, http://tndproject.org
5//
6//      This program is free software: you can redistribute it and/or modify
7//      it under the terms of the GNU Affero General Public License as
8//      published by the Free Software Foundation, either version 3 of the
9//      License, or (at your option) any later version.
10//
11//      This program is distributed in the hope that it will be useful,
12//      but WITHOUT ANY WARRANTY; without even the implied warranty of
13//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14//      GNU Affero General Public License for more details.
15//
16//      You should have received a copy of the GNU Affero General Public License
17//      along with this program.  If not, see <http://www.gnu.org/licenses/>.
18//
19
20// памятка по рефакторингу: к удалению:
21// mysql_
22// rcv
23// getright
24// getpost
25// проверить insert_id
26// AddText -> AddContent
27// SetText -> SetContent
28// Контроль использования html_in
29// Для вывода из базы в html использовать html_out
30
31/**
32@mainpage Cистема комплексного учёта торговли multimag. Документация разработчика.
33<h2>Часто используемые классы</h2>
34BETemplate в core.php содержит шаблонизатор страницы. \n
35doc.core.php содержит основные функции работы с документами \n
36Vitrina (vitrina.php) формирует все страницы витрины и может быть перегружен шаблоном \n
37doc_Nulltype является базовым классом для всех документов системы \n
38BaseReport используется для генерации отчётов \n
39От AsyncWorker наследуются обработчики, выполняющиеся независимо от веб сервера \n
40PosEditor содержит методы для работы с редактором списка товаров \n
41Смотри <a href='annotated.html'>структуры данных</a> и <a href='hierarchy.html'>иерархию классов</a>, чтобы получить полное представление о классах системы
42**/
43
44
45/// Класс для работы с IP адресами IPv6
46class ipv6
47{
48        /// Является ли строка IPv6 адресом ?
49        function is_ipv6($ip = "")
50        {
51                if($ip=='')     return false;
52                if (substr_count($ip,":") > 0 && substr_count($ip,".") == 0)
53                        return true;
54                else    return false;
55        }
56
57        /// Является ли строка IPv4 адресом ?
58        function is_ipv4($ip = "")
59        {
60                if($ip=='')     return false;
61                return !ipv6::is_ipv6($ip);
62        }
63
64        /// Возвращает IP адрес клиента
65        function get_ip()
66        {
67                return  getenv ("REMOTE_ADDR");
68        }
69
70        /// Преобразует заданный IPv6 адрес в полную форму
71        function uncompress_ipv6($ip ="")
72        {
73                if($ip=='')     return false;
74                if(strstr($ip,"::" ))
75                {
76                        $e = explode(":", $ip);
77                        $s = 8-sizeof($e)+1;
78                        foreach($e as $key=>$val)
79                        {
80                                if ($val == "")
81                                        for($i==0;$i<=$s;$i++)          $newip[] = 0;
82                                else    $newip[] = $val;
83                        }
84                        $ip = implode(":", $newip);
85                }
86                return $ip;
87        }
88
89        /// Преобразует заданный IPv6 адрес в краткую форму
90        function compress_ipv6($ip ="")
91        {
92                if($ip=='')     return false;
93                if(!strstr($ip,"::" ))
94                {
95                        $e = explode(":", $ip);
96                        $zeros = array(0);
97                        $result = array_intersect ($e, $zeros );
98                        if (sizeof($result) >= 6)
99                        {
100                                if ($e[0]==0) $newip[] = "";
101                                foreach($e as $key=>$val)
102                                        if ($val !=="0") $newip[] = $val;
103                                $ip = implode("::", $newip);
104                        }
105                }
106                return $ip;
107        }
108}
109
110/// Вычисляет максимально допустимый размер вложений в байтах
111function get_max_upload_filesize()
112{
113    $max_post = trim(ini_get('post_max_size'));
114    $last = strtolower($max_post[strlen($max_post)-1]);
115    switch($last) {
116        // The 'G' modifier is available since PHP 5.1.0
117        case 'g':
118            $max_post *= 1024;
119        case 'm':
120            $max_post *= 1024;
121        case 'k':
122            $max_post *= 1024;
123    }
124
125    $max_fs = trim(ini_get('upload_max_filesize'));
126    $last = strtolower($max_fs[strlen($max_fs)-1]);
127    switch($last) {
128        // The 'G' modifier is available since PHP 5.1.0
129        case 'g':
130            $max_fs *= 1024;
131        case 'm':
132            $max_fs *= 1024;
133        case 'k':
134            $max_fs *= 1024;
135    }
136
137
138    return min($max_fs, $max_post);
139}
140
141/// @brief Форматирование номера телефона, записанного в международном формате, в легкочитаемый вид.
142///
143/// Номера, не начинающиеся с +, возвращаются без форматирования
144function formatPhoneNumber($phone)
145{
146        if($phone[0]!='+')      return $phone;
147        $divs=array('','','-','','','-','','','-','','-','','-','','-','','-','','-','','','','','','','','','','','','','','','','','','','','');
148        $fphone='';
149        $len=strlen($phone);
150        for($i=0;$i<$len;$i++)
151        {
152                $fphone.=$divs[$i].$phone[$i];
153        }
154        return $fphone;
155}
156
157/// @brief Обработчик неперехваченных исключений
158///
159/// Записывает событие в журнал ошибок и выдаёт сообщение. При правильной архитектуре программы никогда не должен быть вызван.
160function exception_handler($exception)
161{
162        global $db;
163        if($db)
164        {
165                $uid=@$_SESSION['uid'];
166                settype($uid,"int");
167                $ip=$db->real_escape_string(getenv("REMOTE_ADDR"));
168                $s=$db->real_escape_string($exception->getMessage());
169                $ag=$db->real_escape_string(getenv("HTTP_USER_AGENT"));
170                $rf=$db->real_escape_string(urldecode(getenv("HTTP_REFERER")));
171                $ff=$db->real_escape_string($_SERVER['REQUEST_URI']);
172                $db->query("INSERT INTO `errorlog` (`page`,`referer`,`msg`,`date`,`ip`,`agent`, `uid`) VALUES
173                ('$ff','$rf','$s',NOW(),'$ip','$ag', '$uid')");
174        }
175        header('HTTP/1.0 500 Internal error');
176        header('Status: 500 Internal error');
177        $s=html_out($exception->getMessage());
178        $ff=html_out($_SERVER['REQUEST_URI']);
179        echo"<!DOCTYPE html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><title>Error 500: Необработанная внутренняя ошибка</title>
180        <style type='text/css'>body{color: #000; background-color: #eee; text-align: center;}</style></head><body>
181        <h1>Необработанная внутренняя ошибка</h1>".get_class($exception).": $s<br>Страница:$ff<br>Сообщение об ошибке передано администратору</body></html>";
182}
183set_exception_handler('exception_handler');
184
185/// Подсветка подстроки в строке, используя span class=b_selection
186/// @param str Исходная строка
187/// @param substr Строка, которую необходимо подсветить
188function SearchHilight($str,$substr)
189{
190        if(!$substr) return $str;
191        $tmp=split($substr,' '.$str.' ');
192        $result='';
193        foreach($tmp as $t)
194        {
195                if(!$result) $result=$t;
196                else $result.="<span class='b_selection'>$substr</span>$t";
197        }
198        return $result;
199}
200
201/// @brief Генератор псевдоуникального кода.
202///
203/// Используется для генерации легкозапоминаемых паролей.
204/// @param num Если true - использовать только цифры.
205/// @param minlen Минимальная длина кода.
206/// @param maxlen Максимальная длина кода.
207function keygen_unique($num=0, $minlen=5, $maxlen=12)
208{
209        if($minlen<1) $minlen=5;
210        if($maxlen>10000) $maxlen=10000;
211        if($maxlen<$minlen) $maxlen=$minlen;
212        if(!$num)
213        {
214                $sstr="bcdfghjklmnprstvwxz";
215                $gstr="aeiouy1234567890aeiouy";
216                $rstr="aeiouy1234567890aeiouybcdfghjklmnprstvwxz";
217                $sln=18; // +1
218                $gln=21; // +1
219                $rln=40; //+1
220        }
221        else
222        {
223                $sstr="135790";
224                $gstr="24680";
225                $rstr="1234567890";
226                $sln=5; // +1
227                $gln=4; // +1
228                $rln=9; //+1
229        }
230        $r=rand(0,$rln);
231        $s=$rstr[$r];
232        $ln=rand($minlen,$maxlen);
233        $sig=0;
234        for($i=1;$i<$ln;$i++)
235        {
236                if(eregi($s[$i-1],$sstr))
237                {
238                        $r=rand(0,$gln);
239                        $s.=$gstr[$r];
240                }
241                else
242                {
243                        $r=rand(0,$sln);
244                        $s.=$sstr[$r];
245                }
246        }
247        return $s;
248}
249
250// ======================================= Обработчики ввода переменных ====================================
251
252/// Обёртка над $_REQUEST, позволяющая задать значение по умолчанию
253/// @param varname Имя элемента $_REQUEST
254/// @param dev Возвращаемое значение, если искомый элемент отсутствует
255function request($varname,$def='')
256{
257        if(isset($_REQUEST[$varname]))  return $_REQUEST[$varname];
258        return $def;
259}
260
261/// Получает часть массива $_REQUEST, позволяет задать значение по умолчанию для отсутствующих элементов
262/// @param varname Массив значений ключенй $_REQUEST
263/// @param dev Возвращаемое значение, если искомый элемент отсутствует
264function requestA($var_array, $def='')
265{
266        $a=array_fill_keys($var_array, $def);
267        $v=array_intersect_key($_REQUEST, $a);
268        $r=array_merge($a,$v);
269        return $r;
270}
271
272/// Безопасное получение целого значения
273function rcvint($varname, $def=0)
274{
275        if(isset($_REQUEST[$varname]))  return intval($_REQUEST[$varname]);
276        return $def;
277}
278
279/// Безопасное получение числа заданной точности
280function rcvrounded($varname, $round=3, $def=0)
281{
282        if(isset($_REQUEST[$varname]))  return round($_REQUEST[$varname],$round);
283        return $def;
284}
285
286/// Безопасное получение строки с датой
287function rcvdate($varname, $def='1970-01-01')
288{
289        if(isset($_REQUEST[$varname]))  return date("Y-m-d", strtotime($_REQUEST[$varname]));
290        return $def;
291}
292
293/// Безопасное получение строки с временем
294function rcvtime($varname, $def='1970-01-01')
295{
296        if(isset($_REQUEST[$varname]))  return date("H:i:s", strtotime($_REQUEST[$varname]));
297        return $def;
298}
299
300/// Безопасное получение строки с датой и временем
301function rcvdatetime($varname, $def='1970-01-01')
302{
303        if(isset($_REQUEST[$varname]))  return date("Y-m-d H:i:s", strtotime($_REQUEST[$varname]));
304        return $def;
305}
306
307/// Преобразование HTML сущностей в их ASCII представление. Обёртка над html_entity_decode.
308function html_in($data)
309{
310        return html_entity_decode($data, ENT_QUOTES, "UTF-8");
311}
312
313/// Обёртка над htmlentities
314function html_out($data)
315{
316        return htmlentities($data, ENT_QUOTES, "UTF-8");
317}
318
319/// Получение пользовательского воода GET или POST методом
320/// TODO: Уже неакутально. Заменить на request в местах использования и удалить.
321function getpost($varname,$def="")
322{
323        $bt=debug_backtrace();
324        trigger_error("Function ".__FUNCTION__." is deprecated (called {$bt[0]['file']}:{$bt[0]['line']}) \n", E_USER_WARNING);
325        if(isset($_POST[$varname]))     return $_POST[$varname];
326        if(isset($_GET[$varname]))      return $_GET[$varname];
327        return $def;
328}
329
330// =================================== Аутентификация и контроль привилегий ============================================
331/// @brief Требование аутентификации.
332///
333/// Выполняет редирект на страницу аутентификации, если аутентификация не пройдена.
334function need_auth()
335{
336        global $tmpl;
337        if(!auth())
338        {
339                $_SESSION['last_page']=$_SERVER['REQUEST_URI'];
340                $_SESSION['cook_test']='data';
341                header('Location: /login.php');
342                $tmpl->msg("Для продолжения необходимо выполнить вход!","info","Требуется аутентификация");
343                $tmpl->write();
344                exit();
345        }
346        return 1;
347}
348
349/// Проверка аутентификации
350function auth()
351{
352        return (@$_SESSION['uid']==0)?0:1;
353}
354
355/// @brief Получить список привилегий (read, write, edit, delete) доступа к указанному объекту.
356/// Не используется для остальных.
357/// @param object Имя объекта, для которого необходимо получить список
358/// @param uid  ID пользователя, для которого необходимо получить список
359/// TODO: Устарело. Не рекомендуется к использованию с версии 0.0.1r221. Убрать использование и функцию.
360function getright($object,$uid)
361{
362        $bt=debug_backtrace();
363        trigger_error("Function ".__FUNCTION__." is deprecated (called {$bt[0]['file']}:{$bt[0]['line']}) \n", E_USER_WARNING);
364        global $db;
365        //throw new Exception("Проверка привилений доступа через удаляемую функцию getright($object,$uid)");
366        if($uid==1)
367        {
368                $nxt['read']=1;
369                $nxt['write']=1;
370                $nxt['edit']=1;
371                $nxt['delete']=1;
372                return $nxt;
373        }
374        return $db->query("
375        SELECT MAX(`users_grouprights`.`a_read`) AS `read`, MAX(`users_grouprights`.`a_write`) AS `write`, MAX(`users_grouprights`.`a_edit`) AS `edit`, MAX(`users_grouprights`.`a_delete`) AS `delete`
376        FROM `users_grouprights`
377        INNER JOIN `users_groups` ON `users_groups`.`gid`=`users_grouprights`.`gid` AND ( `users_groups`.`uid`='$uid'
378        OR `users_groups`.`uid`='0')
379        WHERE `users_grouprights`.`object`='$object'
380        GROUP BY `users_grouprights`.`object`")->fetch_assoc($res);;
381}
382
383/// Есть ли привилегия доступа к указанному объекту для указанной операции
384/// @param object Имя объекта, для которого нужно проверить привилегии
385/// @param action Имя действия, для осуществления которого нужно проверить привилегии
386/// @param no_redirect Если false - то в случае отсутствия привилегий, и если не пройдена аутентификация, выполняет редирект на страницу аутентификации
387function isAccess($object, $action,$no_redirect=false)
388{
389        global $db;
390        $uid=@$_SESSION['uid'];
391        if($uid==1)     return true;
392        $res=$db->query("(
393        SELECT `users_acl`.`id` FROM `users_acl` WHERE `uid`='$uid' AND `object`='$object' AND `action`='$action'
394        ) UNION (
395        SELECT `users_groups_acl`.`id` FROM `users_groups_acl`
396        INNER JOIN `users_in_group` ON `users_in_group`.`gid`=`users_groups_acl`.`gid`
397        WHERE `uid`='$uid' AND `object`='$object' AND `action`='$action')
398        UNION (
399        SELECT `users_groups_acl`.`id` FROM `users_groups_acl`
400        INNER JOIN `users_in_group` ON `users_in_group`.`gid`=`users_groups_acl`.`gid`
401        WHERE `uid`='0' AND `object`='$object' AND `action`='$action')
402        UNION(
403        SELECT `users_acl`.`id` FROM `users_acl` WHERE `uid`='0' AND `object`='$object' AND `action`='$action')");
404        if(!$res)       throw new MysqlException("Выборка привилегий не удалась");
405        $access=($res->num_rows>0)?true:false;
406        if((!$uid) && (!$access) && (!$no_redirect))    need_auth();
407        return $access;
408}
409
410/// Транслитерация строки
411function translitIt($str)
412{
413    $tr = array(
414        "А"=>"A","Б"=>"B","В"=>"V","Г"=>"G",
415        "Д"=>"D","Е"=>"E","Ж"=>"J","З"=>"Z","И"=>"I",
416        "Й"=>"Y","К"=>"K","Л"=>"L","М"=>"M","Н"=>"N",
417        "О"=>"O","П"=>"P","Р"=>"R","С"=>"S","Т"=>"T",
418        "У"=>"U","Ф"=>"F","Х"=>"H","Ц"=>"TS","Ч"=>"CH",
419        "Ш"=>"SH","Щ"=>"SCH","Ъ"=>"","Ы"=>"YI","Ь"=>"",
420        "Э"=>"E","Ю"=>"YU","Я"=>"YA","а"=>"a","б"=>"b",
421        "в"=>"v","г"=>"g","д"=>"d","е"=>"e","ж"=>"j",
422        "з"=>"z","и"=>"i","й"=>"y","к"=>"k","л"=>"l",
423        "м"=>"m","н"=>"n","о"=>"o","п"=>"p","р"=>"r",
424        "с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h",
425        "ц"=>"ts","ч"=>"ch","ш"=>"sh","щ"=>"sch","ъ"=>"y",
426        "ы"=>"yi","ь"=>"","э"=>"e","ю"=>"yu","я"=>"ya"
427    );
428   
429    foreach($tr as $s=>$r)
430        $str=mb_ereg_replace ($s, $r, $str);   
431    return $str;
432}
433
434
435
436// ==================================== Рассылка ===================================================
437
438/// @brief Выполнение рассылки сообщения на электронную почту по базе агентов и зарегистрированных пользователей.
439///
440/// В текст рассылки автоматически добавляется информация о том, как отказаться от рассылки
441/// @param tema Тема сообщения
442/// @param msg Тело сообщения
443function SendSubscribe($tema,$msg)
444{
445        global $CONFIG, $db;
446        $res=$db->query("SELECT `firm_name` FROM `doc_vars` WHERE `id`='{$CONFIG['site']['default_firm']}'");
447        if(!$res)       throw new MysqlException("Ошибка получения наименования организации");
448        list($firm_name)=$res->fetch_row();
449        $res=$db->query("(SELECT `name`, `reg_email` AS `email`, `real_name` FROM `users` WHERE `reg_email_subscribe`='1' AND `reg_email_confirm`='1')
450        UNION
451        (SELECT `name`, `email`, `fullname` AS `real_name` FROM `doc_agent` WHERE `no_mail`='0' AND `email`!='')
452        ");
453        if(!$res)       throw new MysqlException("Ошибка получения списка подписчиков");
454        while($nxt=$res->fetch_assoc($res))
455        {
456                if($nxt['real_name'])   $nxt['name']="{$nxt['real_name']} ({$nxt['name']})";
457                $txt="
458Здравствуйте, {$nxt['name']}!
459
460$tema
461------------------------------------------
462
463$msg
464
465------------------------------------------
466
467Вы получили это письмо потому что подписаны на рассылку сайта {$CONFIG['site']['display_name']} ( http://{$CONFIG['site']['name']} ), либо являетесь клиентом $firm_name.
468Отказаться от рассылки можно, перейдя по ссылке http://{$CONFIG['site']['name']}/login.php?mode=unsubscribe&email={$nxt['email']}
469";
470                mailto($nxt['email'], $tema." - {$CONFIG['site']['name']}", $txt);
471                //mail($nxt['email'],$tema." - {$CONFIG['site']['name']}", $txt ,"Content-type: text/plain; charset=UTF-8\nFrom: {$CONFIG['site']['display_name']} <{$CONFIG['site']['admin_email']}>");
472        }
473}
474
475/// Отправляет оповещение администратору сайта по всем доступным каналам связи
476/// @param text Тело сообщения
477/// @param subject Тема сообщения
478function sendAdmMessage($text,$subject='')
479{
480        global $CONFIG;
481        if($subject=='')        $subject="Admin mail from {$CONFIG['site']}";
482
483        if($CONFIG['site']['doc_adm_email'])
484                mailto($CONFIG['site']['doc_adm_email'],$subject ,$text);
485
486        if($CONFIG['site']['doc_adm_jid'] && $CONFIG['xmpp']['host'])
487        {
488                try
489                {
490                        require_once($CONFIG['location'].'/common/XMPPHP/XMPP.php');
491                        $xmppclient = new XMPPHP_XMPP( $CONFIG['xmpp']['host'], $CONFIG['xmpp']['port'], $CONFIG['xmpp']['login'], $CONFIG['xmpp']['pass'], 'xmpphp', '');
492                        $xmppclient->connect();
493                        $xmppclient->processUntil('session_start');
494                        $xmppclient->presence();
495                        $xmppclient->message($CONFIG['site']['doc_adm_jid'], $text);
496                        $xmppclient->disconnect();
497                }
498                catch(XMPPHP_Exception $e)
499                {
500                        $tmpl->logger("Невозможно отправить сообщение по XMPP!","err");
501                }
502        }
503}
504
505/// Получить ID цены текущего пользователя
506function getCurrentUserCost()
507{
508        global $db;
509        if(@$_SESSION['uid'])   $res=$db->query("SELECT `id` FROM `doc_cost` WHERE `vid`='-1'");
510        else                    $res=$db->query("SELECT `id` FROM `doc_cost` WHERE `vid`='1'");
511        if(!$res)               throw new MysqlException('Не удалось выбрать цену для пользователя');
512        if($res->num_rows<1)    throw new Exception("Не найдено связанных с пользователем цен!");
513        $row=$res->fetch_row();
514        return $row[0];
515}
516
517
518/// Загрузка шаблона с заданным названием
519function SafeLoadTemplate($template)
520{
521        global $tmpl, $CONFIG;
522        if($template)   $tmpl->loadTemplate($template);
523}
524
525/// Получить данные профиля пользователя по uid
526function getUserProfile($uid)
527{
528        global $db;
529        settype($uid,'int');
530        $user_profile=array();
531        $user_profile['main']=array();
532        $user_profile['dop']=array();
533
534        $res=$db->query("SELECT * FROM `users` WHERE `id`='$uid'");
535        if(!$res)       throw new MysqlException("Не удалось получить основные данные пользователя!");
536        if(!$res->num_rows)     return $user_profile;   // Если не найден
537        $user_profile['main']   = $res->fetch_assoc();
538        unset($user_profile['main']['pass']);   // В целях безопасности
539        unset($user_profile['main']['pass_change']);
540        $res=$db->query("SELECT `param`,`value` FROM `users_data` WHERE `uid`='$uid'");
541        if(!$res)       throw new MysqlException("Не удалось получить дополнительные данные пользователя!");
542        while($nn=$res->fetch_row())
543        {
544                $user_profile['dop'][$nn[0]]=$nn[1];
545        }
546        return $user_profile;
547}
548
549/// Класс шаблонизатора вывода страницы. Содержит методы, отвечающие за загрузку темы оформления, заполнения страницы содержимым и отправки в броузер
550class BETemplate
551{
552        var $tpl;                       ///< Шаблон
553        var $ajax=0;                    ///< Флаг ajax выдачи
554        var $tplname;                   ///< Наименование загруженного шаблона
555        var $page_blocks=array();       ///< Новые блоки шаблонизатора. Ассоциативный массив. Замена устаревшего $page
556        var $hide_blocks=array();       ///< Скрытые блоки. Блоки, отображать которые не нужно
557
558        function __construct()
559        {
560                global $CONFIG;
561                if($CONFIG['site']['skin'])     $this->loadTemplate($CONFIG['site']['skin']);
562                else                            $this->loadTemplate('default');
563        }
564        /// Загрузка шаблона по его имени
565        function loadTemplate($s)
566        {
567                $this->tplname=$s;
568                $fd=@file('skins/'.$s.'/style.tpl');
569                if($fd)
570                {
571                        $this->tpl="";
572                        foreach($fd as $item)
573                                $this->tpl.=$item;
574                }
575        }
576
577        /// Установить флаг скрытия заданной части страницы
578        /// @param block Имя блока страницы
579        function hideBlock($block)
580        {
581                $this->hide_blocks[$block]=true;
582        }
583
584        /// Снять флаг скрытия заданной части страницы
585        /// @param block Имя блока страницы
586        function showBlock($block)
587        {
588                unset($this->hide_blocks[$block]);
589        }
590
591        /// Задать HTML содержимое шапки страницы
592        function setTop($s)
593        {
594                @$this->page_blocks['top']=$s;
595        }
596
597        /// Добавить HTML содержимое в конец шапки страницы
598        function addTop($s)
599        {
600                @$this->page_blocks['top'].=$s;
601        }
602
603        /// Задать HTML содержимое правой колонки страницы
604        function setRight($s)
605        {
606                @$this->page_blocks['right']=$s;
607        }
608
609        /// Вставить HTML содержимое в начало правой колонки страницы
610        function insRight($s)
611        {
612                @$this->page_blocks['right']=$s.$this->page_blocks['right'];
613        }
614
615        /// Добавить HTML содержимое в конец правой колонки страницы
616        function addRight($s)
617        {
618                @$this->page_blocks['right'].=$s;
619        }
620
621        /// Вставить HTML содержимое в начало левой колонки страницы
622        function addLeft($s)
623        {
624                @$this->page_blocks['left'].=$s;
625        }
626
627        /// Задать HTML содержимое левой колонки страницы
628        function setLeft($s)
629        {
630                @$this->page_blocks['left']=$s;
631        }
632
633        /// Задать текст заголовка (обычно тэг title) страницы
634        function setTitle($s)
635        {
636                @$this->page_blocks['title']=$s;
637        }
638
639        /// Задать содержимое мета-тэга keywords
640        function setMetaKeywords($s)
641        {
642                @$this->page_blocks['meta_keywords']=$s;
643        }
644
645        /// Задать содержимое мета-тэга description
646        function setMetaDescription($s)
647        {
648                @$this->page_blocks['meta_description']=$s;
649        }
650
651        /// Задать HTML содержимое основного блока страницы (content)
652        function setContent($s)
653        {
654                @$this->page_blocks['content']=$s;
655        }
656
657        /// Добавить HTML содержимое к основному блоку страницы (content)
658        function addContent($s)
659        {
660                @$this->page_blocks['content'].=$s;
661        }
662
663        /// Добавить содержимое к таблице стилей страницы (тэг style)
664        function addStyle($s)
665        {
666                @$this->page_blocks['stylesheet'].=$s;
667        }
668
669        /// Задать содержимое к пользовательского блока страницы
670        /// @param block_name Имя блока. Не должно совпадать с именами стандартных блоков.
671        /// @param data HTML данные блока
672        function setCustomBlockData($block_name, $data)
673        {
674                @$this->page_blocks[$block_name]=$data;
675        }
676        /// Добавить содержимое к пользовательскому блоку страницы
677        /// @param block_name Имя блока. Не должно совпадать с именами стандартных блоков.
678        /// @param data HTML данные блока
679        function addCustomBlockData($block_name, $data)
680        {
681                @$this->page_blocks[$block_name].=$data;
682        }
683
684        /// Добавить блок (div) с информацией к основному блоку страницы (content)
685        /// @param text Текст сообщения
686        /// @param mode Вид сообщения: ok - сообщение об успехе, err - сообщение об ошибке, info - информационное сообщение
687        /// @param head Заголовок сообшения
688        function msg($text="",$mode="",$head="")
689        {
690                if($text=="") return;
691                if($mode=="error") $mode="err";
692                if($mode=='info') $mode='notify';
693                if(($mode!="ok")&&($mode!="err")) $mode="notify";
694                if($head=="")
695                {
696                        $msg="Информация:";
697                        if($mode=="ok") $msg="Сделано!";
698                        if($mode=="err") $msg="Ошибка!";
699                }
700                else $msg=$head;
701
702                @$this->page_blocks['content'].="<div class='$mode'><b>$msg</b><br>$text</div>";
703        }
704
705        /// Сформировать HTML и отправить его, в соответствии с загруженным шаблоном и установленным содержимым блоков
706        function write()
707        {
708                global $time_start;
709                if(stripos(getenv("HTTP_USER_AGENT"), "MSIE" )!==FALSE )
710                {
711                        $this->page_blocks['notsupportbrowser']="<div style='background: #ffb; border: 1px #fff outset; padding: 3px; padding-right: 15px; text-align: right; font-size: 14px;'><img src='/img/win/important.png' alt='info' style='float: left'>
712                        Вероятно, Вы используете неподдерживаемую версию броузера.<br><b>Для правильной работы сайта, скачайте и установите последнюю версию <a href='http://mozilla.com'>Mozilla</a>, <a href='http://www.opera.com/download/'>Opera</a> или <a href='http://www.google.com/intl/ru/chrome/browser/'>Chrome</a></b><div style='clear: both'></div></div>";
713                }
714                $time = microtime(true) - $time_start;
715                $this->page_blocks['gentime']=round($time,4);
716
717                @include_once("skins/".$this->tplname."/style.php");
718                if($this->ajax)         echo @$this->page_blocks['content'];
719                else
720                {
721                        @include_once("skins/".$this->tplname."/style.php");
722                        if(function_exists('skin_prepare'))
723                        {
724                                $res=skin_prepare();
725                        }
726
727                        if(function_exists('skin_render'))
728                        {
729                                $res=skin_render($this->page_blocks,$this->tpl);
730                        }
731                        else
732                        {
733                                $signatures=array();
734                                foreach($this->page_blocks as $key => $value)
735                                {
736                                        $signatures[]="<!--site-$key-->";
737                                }
738                                $res=str_replace($signatures,$this->page_blocks,$this->tpl);
739                        }
740                        echo"$res";
741                }
742                $time = microtime(true) - $time_start;
743                if($time>=3)
744                        $this->logger("Exec time: $time",1);    /// Записывам ошибку, если скрипт долго работает
745        }
746
747        /// Записать сообщение об ошибке в журнал и опционально вывести на страницу
748        /// @param s Основной текст сообщения
749        /// @param silent Если TRUE, то сообщение не выводится на страницу. FALSE по умолчанию.
750        /// @param hidden_data Скрытый текст сообщения об ошибке. Заносится в журнал, на страницу не выводится.
751        /// TODO: нужен класс регистрации ошибок, с уровнями ошибок, возможностью записи в файл, отправки на email, jabber, sms и пр.
752        function logger($s, $silent=0, $hidden_data='')
753        {
754                global $db;
755                if(isset($_SESSION['uid']))     $uid=$_SESSION['uid'];
756                else $uid=0;
757                settype($uid, "int");
758                $ip=$db->real_escape_string(getenv("REMOTE_ADDR"));
759                $s_sql=$db->real_escape_string($s);
760                $ag=$db->real_escape_string(getenv("HTTP_USER_AGENT"));
761                $rf=$db->real_escape_string(urldecode(getenv("HTTP_REFERER")));
762                $ff=$db->real_escape_string($_SERVER['REQUEST_URI']);
763                $db->query("INSERT INTO `errorlog` (`page`,`referer`,`msg`,`date`,`ip`,`agent`, `uid`) VALUES
764                ('$ff','$rf','$s_sql',NOW(),'$ip','$ag', '$uid')");
765
766                if(!$silent)
767                {
768                        $s=html_out($s);
769                        $ff=html_out($_SERVER['REQUEST_URI']);
770                        $this->msg("$s<br>Страница:$ff<br>Сообщение об ошибке передано администратору","err","Внутренняя ошибка!");
771                }
772                return $db->insert_id;
773        }
774};
775
776/// Класс-исключение используется для информирования о отсутствии привилегий на доступ к запрошенной функции
777class AccessException extends Exception
778{
779        function __construct($text='')
780        {
781                parent::__construct($text);
782        }
783};
784
785/// Класс-исключение используется для информирования о отсутствии запрашиваемого объекта. Устанавливает заголовок 404 Not found
786class NotFoundException extends Exception
787{
788        function __construct($text='')
789        {
790                header('HTTP/1.0 404 Not found');
791                parent::__construct($text);
792        }
793};
794
795/// Класс-исключение используется для информирования об ошибке при выполнении myqsl запроса
796class MysqlException extends Exception
797{
798        var $sql_error;
799        var $sql_errno;
800        var $db;
801        function __construct($text,$_db=0)
802        {
803                global $db;
804                if(!$_db)       $_db=$db;
805                $this->db=$_db;
806                $this->sql_error=$this->db->error;
807                $this->sql_errno=$this->db->errno;
808                switch($this->sql_errno)
809                {
810                        case 1062:      $text.=" {$this->sql_errno}:Дублирование - такая запись уже существует в базе данных. Исправьте данные, и попробуйте снова.";   break;
811                        case 1452:      $text.=" {$this->sql_errno}:Нарушение связи - введённые данные недопустимы, либо предпринята попытка удаления объекта, от которого зависят другие объекты. Проверьте правильность заполнения полей.";   break;
812                }
813                parent::__construct($text);
814                $this->WriteLog();
815        }
816
817        /// Записывает событие в журнал ошибок
818        /// TODO: нужен класс регистрации ошибок, с уровнями ошибок, возможностью записи в файл, отправки на email, jabber, sms и пр.
819        function WriteLog()
820        {
821                global $db;
822                $uid=@$_SESSION['uid'];
823                settype($uid,"int");
824                $ip=$db->real_escape_string(getenv("REMOTE_ADDR"));
825                $s=$db->real_escape_string(get_class($this).': '.$this->message .' '. $this->sql_errno . ': ' . $this->sql_error);
826                $ag=$db->real_escape_string(getenv("HTTP_USER_AGENT"));
827                $rf=$db->real_escape_string(urldecode(getenv("HTTP_REFERER")));
828                $ff=$db->real_escape_string($_SERVER['REQUEST_URI']);
829                $db->query("INSERT INTO `errorlog` (`page`,`referer`,`msg`,`date`,`ip`,`agent`, `uid`) VALUES
830                ('$ff','$rf','$s',NOW(),'$ip','$ag', '$uid')");
831        }
832};
833
834
835/// Базовый класс для создания автожурналируемых исключений
836class AutoLoggedException extends Exception
837{
838        function __construct($text='')
839        {
840                parent::__construct($text);
841                $this->WriteLog();
842        }
843
844        /// Записывает событие в журнал ошибок
845        /// TODO: нужен класс регистрации ошибок, с уровнями ошибок, возможностью записи в файл, отправки на email, jabber, sms и пр.
846        protected function WriteLog()
847        {
848                global $db;
849                $uid=$_SESSION['uid'];
850                settype($uid,"int");
851                $ip=$db->real_escape_string(getenv("REMOTE_ADDR"));
852                $s=$db->real_escape_string (get_class($this).': '.$this->message);
853                $ag=$db->real_escape_string(getenv("HTTP_USER_AGENT"));
854                $rf=$db->real_escape_string(urldecode(getenv("HTTP_REFERER")));
855                $ff=$db->real_escape_string($_SERVER['REQUEST_URI']);
856                $db->query("INSERT INTO `errorlog` (`page`,`referer`,`msg`,`date`,`ip`,`agent`, `uid`) VALUES
857                ('$ff','$rf','$s',NOW(),'$ip','$ag', '$uid')");
858        }
859};
860
861//class DB extends MysqiExtended {
862//      protected static $_instance;
863//      private function __construct(){}
864//      private function __clone() {}
865//      private function __wakeup() {}
866//     
867//      public static function getInstance(){
868//              if (self::$_instance === null) {
869//              self::$_instance = new self;   
870//              }
871//      return self::$_instance;
872//      }
873//};
874
875
876if(!function_exists('mysqli_query'))
877{
878        header("HTTP/1.0 500 Internal Server Error");
879        die("<h1>500 Внутренняя ошибка сервера</h1>Расширение php-mysqli не найдено. Программа установлена некорректно. Обратитесь к администратору c описанием проблемы.");
880}
881
882if(!function_exists('mb_internal_encoding'))
883{
884        header("HTTP/1.0 500 Internal Server Error");
885        die("<h1>500 Внутренняя ошибка сервера</h1>Расширение php-mbstring не найдено. Программа установлена некорректно. Обратитесь к администратору c описанием проблемы.");
886}
887
888$time_start = microtime(true);
889if(!function_exists('mb_internal_encoding'))
890{
891        header("HTTP/1.0 500 Internal Server Error");
892        die("<h1>500 Внутренняя ошибка сервера</h1>Расширение mbstring не установлено! Программа установлена некорректно. Обратитесь к администратору c описанием проблемы.");
893}
894
895session_start();
896mb_internal_encoding("UTF-8");
897
898$base_path = dirname(dirname(__FILE__));
899if(! include_once("$base_path/config_site.php"))
900{
901        header("HTTP/1.0 500 Internal Server Error");
902        die("<h1>500 Внутренняя ошибка сервера</h1>Конфигурационный файл не найден! Программа установлена некорректно. Обратитесь к администратору c описанием проблемы.");
903}
904
905include_once($CONFIG['location']."/common/core.common.php");
906
907if($CONFIG['site']['force_https'])
908        header('Location: https://'.$_SERVER["HTTP_HOST"].$_SERVER['REQUEST_URI'], true, 301);
909
910if(!isset($CONFIG['site']['display_name']))     $CONFIG['site']['display_name']=$CONFIG['site']['name'];
911
912
913
914$db = @ new MysqiExtended($CONFIG['mysql']['host'], $CONFIG['mysql']['login'], $CONFIG['mysql']['pass'], $CONFIG['mysql']['db']);
915
916
917
918if($db->connect_error)
919{
920        header("HTTP/1.0 503 Service temporary unavariable");
921        die("<h1>503 Сервис временно недоступен!</h1>Не удалось соединиться с сервером баз данных. Возможно он перегружен, и слишком медленно отвечает на запросы, либо выключен. Попробуйте подключиться через 5 минут. Если проблема сохранится - пожалуйста, напишите письмо <a href='mailto:{$CONFIG['site']['admin_email']}'>{$CONFIG['site']['admin_email']}</a> c описанием проблемы: ErrorCode: {$db->connect_errno} ({$db->connect_error})");
922}
923
924// Включаем автоматическую генерацию исключений для mysql
925mysqli_report(MYSQLI_REPORT_STRICT | MYSQLI_REPORT_ERROR);
926
927if(!$db->set_charset("utf8"))
928{
929    header("HTTP/1.0 503 Service temporary unavariable");
930    die("<h1>503 Сервис временно недоступен!</h1>Невозможно задать кодировку соединения с базой данных: ".$db->error);
931}
932
933
934// m_ysql_query("SET CHARACTER SET UTF8");
935// m_ysql_query("SET character_set_client = UTF8");
936// m_ysql_query("SET character_set_results = UTF8");
937// m_ysql_query("SET character_set_connection = UTF8");
938
939header("X-Powered-By: MultiMag ".MULTIMAG_VERSION);
940
941/// TODO: Убрать обращения этих переменных из других файлов, и сделать их локальными
942$tim=time();
943$ip=$db->real_escape_string(getenv("REMOTE_ADDR"));
944$ag=$db->real_escape_string(getenv("HTTP_USER_AGENT"));
945$rf=$db->real_escape_string(urldecode(getenv("HTTP_REFERER")));
946$qq=$db->real_escape_string(urldecode($_SERVER['REQUEST_URI'].'?'.$_SERVER['QUERY_STRING']));
947$ff=$db->real_escape_string($_SERVER['SCRIPT_NAME']);
948
949if(!isset($_REQUEST['ncnt']))
950{
951        $db->query("INSERT INTO `counter` (`date`,`ip`,`agent`,`refer`,`query`,`file`) VALUES ('$tim','$ip','$ag','$rf','$qq','$ff')");
952}
953
954/// TODO: Пересмотреть принцип работы со скидками
955$skidka="";
956
957$tmpl=new BETemplate;
958
959/// Глобальная переменная должна быть заменена в местах использования на $_REQUEST['mode']
960if(isset($_REQUEST['mode']))    $mode=$_REQUEST['mode'];
961else                            $mode='';
962
963/// Нужно вычистить глобальную переменную UID везде
964if(isset($_SESSION['uid']))     $uid=$_SESSION['uid'];
965else                            $uid=0;
966
967/// Должно быть убрано, должно подключаться и создаваться по необходимости
968require_once("include/imgresizer.php");
969require_once("include/wikiparser.php");
970
971$wikiparser=new WikiParser();
972$wikiparser->reference_wiki     = "/wiki/";
973$wikiparser->reference_site     = @($_SERVER['HTTPS']?'https':'http')."://{$_SERVER['HTTP_HOST']}/";
974$wikiparser->image_uri          = "/share/var/wikiphoto/";
975$wikiparser->ignore_images      = false;
976
977$dop_status=array('new'=>'Новый', 'err'=>'Ошибочный', 'inproc'=>'В процессе', 'ready'=>'Готов', 'ok'=>'Отгружен');
978if(is_array(@$CONFIG['doc']['status_list']))    $CONFIG['doc']['status_list']=array_merge($dop_status, $CONFIG['doc']['status_list']);
979else                                            $CONFIG['doc']['status_list']=$dop_status;
980?>
Note: See TracBrowser for help on using the repository browser.