Логирование действий пользователей (всплывающее окно на AJAX)

Логирование действий пользователей (всплывающее окно на AJAX) 1.0.0

Compatibility
not tested for compatibility
Database changes
not required
Additional requirements
sqlite3
Author
frost444
Public domain
yes
Описание: добавляет логирование действий пользователей, их точное месторасположение на трекере.

Возможности:
  • Запись лога перемещения пользователя по трекеру
  • Живой вывод тех кто смотрит топик или форум
  • Использование AJAX и sqlite3
Installation instructions
PHP:
Автор мода: frost444

####[ОТКРЫТЬ]----- config.php
-----[найти]-----

    'bb_login_err'   => array('filecache',   array()),

-----[добавить ниже]-----

    'buf_where'      => array('db_sqlite',   array('columns' => 'user_ip INT, username TEXT, user_id INT, user_rank INT, user_opt INT, page_id INT, id INT, title TEXT, mode TEXT, url TEXT, time INT')),

-----[добавить в конец]-----
$bb_cfg['bots_conf'] = array(
    'id' => '-777',
);
$bb_cfg['bots'] = array (
    'AdsBot-Google' => 'AdsBot [Google]',
    'ia_archiver' => 'Alexa [Bot]',
    'Scooter/' => 'Alta Vista [Bot]',
    'Ask Jeeves' => 'Ask Jeeves [Bot]',
    'Baiduspider+(' => 'Baidu [Spider]',
    'Exabot/' => 'Exabot [Bot]',
    'FAST Enterprise Crawler' => 'FAST Enterprise [Crawler]',
    'FAST-WebCrawler/' => 'FAST WebCrawler [Crawler]',
    'http://www.neomo.de/' => 'Francis [Bot]',
    'Gigabot/' => 'Gigabot [Bot]',
    'Mediapartners-Google' => 'Google Adsense [Bot]',
    'Google Desktop' => 'Google Desktop',
    'Feedfetcher-Google' => 'Google Feedfetcher',
    'Googlebot' => 'Google [Bot]',
    'heise-IT-Markt-Crawler' => 'Heise IT-Markt [Crawler]',
    'heritrix/1.' => 'Heritrix [Crawler]',
    'ibm.com/cs/crawler' => 'IBM Research [Bot]',
    'ICCrawler - ICjobs' => 'ICCrawler - ICjobs',
    'ichiro/' => 'ichiro [Crawler]',
    'MJ12bot/' => 'Majestic-12 [Bot]',
    'MetagerBot/' => 'Metager [Bot]',
    'msnbot-NewsBlogs/' => 'MSN NewsBlogs',
    'msnbot/' => 'MSN [Bot]',
    'msnbot-media/' => 'MSNbot Media',
    'NG-Search/' => 'NG-Search [Bot]',
    'http://lucene.apache.org/nutch/' => 'Nutch [Bot]',
    'NutchCVS/' => 'Nutch/CVS [Bot]',
    'OmniExplorer_Bot/' => 'OmniExplorer [Bot]',
    'online link validator' => 'Online link [Validator]',
    'psbot/0' => 'psbot [Picsearch]',
    'Seekbot/' => 'Seekport [Bot]',
    'Sensis Web Crawler' => 'Sensis [Crawler]',
    'SEO search Crawler/' => 'SEO Crawler',
    'Seoma [SEO Crawler]' => 'Seoma [Crawler]',
    'SEOsearch/' => 'SEOSearch [Crawler]',
    'Snappy/1.1 ( http://www.urltrends.com/ )' => 'Snappy [Bot]',
    'http://www.tkl.iis.u-tokyo.ac.jp/~crawler/' => 'Steeler [Crawler]',
    'SynooBot/' => 'Synoo [Bot]',
    '[email protected]' => 'Telekom [Bot]',
    'TurnitinBot/' => 'TurnitinBot [Bot]',
    'voyager/1.0' => 'Voyager [Bot]',
    'W3 SiteSearch Crawler' => 'W3 [Sitesearch]',
    'W3C-checklink/' => 'W3C [Linkcheck]',
    'W3C_*Validator' => 'W3C [Validator]',
    'http://www.WISEnutbot.com' => 'WiseNut [Bot]',
    'yacybot' => 'YaCy [Bot]',
    'Yahoo-MMCrawler/' => 'Yahoo MMCrawler [Bot]',
    'Yahoo! DE Slurp' => 'Yahoo Slurp [Bot]',
    'Yahoo! Slurp' => 'Yahoo [Bot]',
    'YahooSeeker/' => 'YahooSeeker [Bot]',
    'Yandex/1.01.001 (compatible; Win16; I)' => 'Яндекс БОТ',
    'Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)' => 'Яндекс [Bot]',
    'bingbot/' => 'Bing [Bot]',
);

$bb_cfg['where_user'] = true;

####[СОХРАНИТЬ_ФАЙЛ]####

####[ОТКРЫТЬ]----- ajax.php
-----[найти]-----

        'index_data'        => array('guest'),

-----[добавить ниже]-----

        'UserStats'         => array('user'),
       
-----[найти последнюю скобку и перед ней добавить]-----

    function UserStats()
    {
        require(AJAX_DIR .'UserStats.php');
    }

####[СОХРАНИТЬ_ФАЙЛ]####

####[ОТКРЫТЬ]----- lang_main.php
-----[в конец]-----

// Online/Offline
$lang['OFFLINE'] = 'Вне форума';
$lang['ONLINE'] = 'На форуме';
$lang['HIDDEN'] = 'Скрыт';
$lang['ON_OFF_STATUS'] = 'Статус';
// Online/Offline

$lang['LAST_TYPE'] = 'Последнее действие';
$lang['ONLINE_USERS_WHERE'] = '<b>%1$d</b> человек просматривают эту страницу: <b>%2$d</b><sup title="С 1-го аккаунта сидят несколько человек"><b>[%3$d]</b></sup> зарегистрированных, <b>%4$d</b> скрытых, <b>%5$d</b> гостей, <b>%6$d</b> ботов';

####[СОХРАНИТЬ_ФАЙЛ]####

####[ОТКРЫТЬ]----- index.php
-----[найти]-----

$template->assign_vars(array(
    'SHOW_FORUMS'           => $forums_count,

-----[добавить выше]-----

where_user(array('page_id' => PAGE_FORUM, 'id' => '0', 'mode' => '0', 'url' => str_replace($bb_cfg['script_path'], "", $_SERVER['REQUEST_URI']), 'title' => $lang['FORUM']));

####[СОХРАНИТЬ_ФАЙЛ]####

####[ОТКРЫТЬ]----- viewtopic.php
-----[найти]-----

$template->assign_vars(array(
    'PAGE_URL'            => $pg_url,
   
-----[добавить выше]-----

where_user(array('page_id' => PAGE_VIEWTOPIC, 'id' => $topic_id, 'mode' => '0', 'url' => str_replace($bb_cfg['script_path'], "", $_SERVER['REQUEST_URI']), 'title' => $t_data['topic_title']), true);
   
-----[найти]-----

$template->assign_vars(array(
    'PAGE_URL'            => $pg_url,

-----[добавить ниже]-----

    'WHO_ONLINE_LIST'      => who_online_list(PAGE_VIEWTOPIC, $topic_id),

####[СОХРАНИТЬ_ФАЙЛ]####

####[ОТКРЫТЬ]----- functions.php
-----[найти]-----

function profile_url($data)
{
    ...
}

-----[заменить]-----

function profile_url($data, $popupon = false)
{
    global $bb_cfg, $lang, $datastore;

    if (!$ranks = $datastore->get('ranks'))
    {
        $datastore->update('ranks');
        $ranks = $datastore->get('ranks');
    }

    $user_rank = !empty($data['user_rank']) ? $data['user_rank'] : 0;

    if(isset($ranks[$user_rank]))
    {
        $title = $ranks[$user_rank]['rank_title'];
        $style = $ranks[$user_rank]['rank_style'];
    }
    if(empty($title)) $title = $lang['USER'];
    if(empty($style)) $style = 'colorUser';

    if(!$bb_cfg['color_nick']) $style = '';

    $username = !empty($data['username']) ? $data['username'] : $lang['GUEST'];
    $user_id = (!empty($data['user_id']) && $username != $lang['GUEST']) ? $data['user_id'] : ANONYMOUS;
    if($popupon)
    {
        $profile = "&nbsp;<span onclick=\"user_stats(".$user_id.", 'popup');\" title=\"Просмотр профиля\" class=\"UserPopupsImg clickable\"><span class=\"pad_6\"></span></span>";
        $profile = '<span title="'. $title .'" class="'. $style .'">'. $username .'</span>'.$profile.'';
    }else{
        $profile = '<span title="'. $title .'" class="'. $style .'">'. $username .'</span>';
    }
   
    if(!in_array($user_id, array('', ANONYMOUS, BOT_UID)) && $username && !$popupon)
    {
        $popup = "&nbsp;<span onclick=\"user_stats(".$user_id.", 'popup');\" title=\"Просмотр профиля\" class=\"UserPopupsImg clickable\"><span class=\"pad_6\"></span></span>";
        $profile = '<a href="'. make_url(PROFILE_URL . $user_id, true) .'">'. $profile .'</a>'.$popup.'';
    }

    return $profile;
}


-----[добавить в конец]-----

function who_online_list ($page_id, $id = false, $mode = false)
{
    global $bb_cfg, $lang, $userdata;

    $id = ($id) ? "AND id = {$id}" : '';
    $mode = ($mode) ? "AND mode = {$mode}" : '';
    $where_time = (TIMENOW - 300);
    $sql = CACHE('buf_where')->fetch_rowset("
    SELECT username, user_rank, user_opt, user_id, min(user_ip) as user_ip FROM buf_where
        WHERE page_id = {$page_id}
        $id
        $mode
        AND time > $where_time
        GROUP BY user_ip
        having min(user_ip) = max(user_ip)
    ");
    $id_user = $id_user_hidden = $id_anon = $id_bot = $user = $count_all = array();
    foreach ($sql as $row)
    {   
        $count_all[] = $row['user_ip'];
        if($row['user_id'] != ANONYMOUS && $row['user_id'] != $bb_cfg['bots_conf']['id'])
        {
            $id_user[] = $row['user_id'];
            $user[] = profile_url(array('username' => $row['username'], 'user_id' => $row['user_id'], 'user_rank' => $row['user_rank']));
        }
        else if($row['user_id'] != ANONYMOUS && $row['user_id'] != $bb_cfg['bots_conf']['id'] && bf($row['user_opt'], 'user_opt', 'allow_viewonline'))
        {
            $id_user_hidden[] = $row['user_id'];
        }
        else if($row['user_id'] == ANONYMOUS)
        {
            $id_anon[] = $row['user_id'];
        }
        else if($row['user_id'] == $bb_cfg['bots_conf']['id'])
        {
            $id_bot[] = $row['user_id'];
        }
    }
    $alls = count($count_all);
    $users = count(array_unique($id_user));
    $hiddens = count(array_unique($id_user_hidden));
    $anons = count($id_anon);
    $bots = count($id_bot);
    $duble = ($alls - $users - $hiddens - $anons - $bots);
    $online_count = sprintf($lang['ONLINE_USERS_WHERE'], $alls, $users, $duble, $hiddens, $anons, $bots);
    $online_list = $online_count . '<br /><br />' . join(",\n", array_unique($user));
   
    return $online_list;
}

function where_user($data, $quest = false)
{
    global $bb_cfg, $lang, $userdata;

    if(!$bb_cfg['where_user']) return;
    if(IS_GUEST && !$quest) return;

    $where_time = (TIMENOW - 300);
    $buf = CACHE('buf_where')->fetch_row("
            SELECT time FROM buf_where
            WHERE page_id    = {$data['page_id']}
                AND mode      = '{$data['mode']}'
                AND user_ip  = '". USER_IP ."'
                AND time     > $where_time
                AND id       = {$data['id']}
            ORDER BY time DESC");
    $insert = true;
    if($buf) $insert = false;

    $sql['user_ip']    = USER_IP;
    $sql['username']   = $userdata['username'];
    $sql['user_id']    = $userdata['user_id'];

    if(IS_GUEST)
    {
        $user_browser = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'not browser';

        foreach ($bb_cfg['bots'] as $bot => $name)
        {
            if(strstr($user_browser, $bot))
            {
                $sql['username'] = $name;
                $sql['user_id']  = $bb_cfg['bots_conf']['id'];
            }
        }
    }

    $sql['user_rank']    = $userdata['user_rank'];
    $sql['user_opt']    = $userdata['user_opt'];
    $sql['time']        = TIMENOW;
    $sql['page_id']        = @$data['page_id'];
    $sql['id']            = @$data['id'];
    $sql['mode']        = @$data['mode'];
    $sql['url']            = @$data['url'];
    $sql['title']        = @htmlCHR($data['title']);

    $sql_insert = DB()->build_array('INSERT', $sql);
    if($insert) CACHE('buf_where')->query("INSERT INTO buf_where $sql_insert");
}

####[СОХРАНИТЬ_ФАЙЛ]####

####[ОТКРЫТЬ]----- init_bb.php
-----[найти]-----

define('POST_USERS_URL',  'u');

-----[добавить ниже]-----

//[START] Where user
define('PAGE_REGISTER',                -1);
define('PAGE_LOGIN',                0);
define('PAGE_INDEX',                1);
define('PAGE_FORUM',                2);
define('PAGE_VIEWFORUM',            3);
define('PAGE_VIEWTOPIC',            4);
define('PAGE_POSTING',                5);
define('PAGE_PROFILE',                6);
define('PAGE_PRIVMSGS',                7);
define('PAGE_SEARCH',                8);
define('PAGE_TRACKER',                9);
define('PAGE_VIEWONLINE',            10);
define('PAGE_VIEWMEMBERS',            11);
define('PAGE_GROUPCP',                12);
define('PAGE_FAQ',                    13);
define('PAGE_REPORT',                14);
define('PAGE_PORTAL',                15);
define('PAGE_ORDER',                16);
define('PAGE_POINTSCP',                17);
define('PAGE_QUESTBOOK',            18);
define('PAGE_RADIO',                19);
define('PAGE_PRESENTS',                20);
define('PAGE_VIEWCHEATER',            21);
define('PAGE_WARNINGS',                22);
define('PAGE_MYTOP',                22);
////(BLOG)(START) Where user
define('PAGE_BLOG',                    100);
define('PAGE_BLOG_ALLENTRIES',        101);
define('PAGE_BLOG_BLOCKED',            102);
define('PAGE_BLOG_CFG',                103);
define('PAGE_BLOG_CONTRIBUTORS',    104);
define('PAGE_BLOG_ENTRY',            105);
define('PAGE_BLOG_FRIENDS',            106);
define('PAGE_BLOG_FPOSTING',        107);
define('PAGE_BLOG_RSS',                108);
define('PAGE_BLOGS',                109);
define('PAGE_BLOGS_NEWS',            110);
////(BLOG)(END) Where user
////(GRABBER)(START) Where user
define('PAGE_RUTOR',                200);
define('PAGE_RUTORREGISTER',        201);
define('PAGE_RELEASE',                202);
define('PAGE_GRAB_INDEX',            203);
define('PAGE_QUOTE',                204);
////(GRABBER)(END) Where user
//[END] Where user
           
####[СОХРАНИТЬ_ФАЙЛ]####
####[ОТКРЫТЬ]----- init_bb.php
-----[найти]-----

                    case 'db_sqlite':
                        if (!isset($this->obj[$cache_name]))
                        {
                            $cache_cfg['pconnect']     = $this->cfg['pconnect'];
                            $cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db');
                            $cache_cfg['table_name']   = $cache_name;
                            $cache_cfg['table_schema'] = $this->get_table_schema($cache_cfg);

                            $this->obj[$cache_name] = new sqlite_common($cache_cfg);
                        }
                        $this->ref[$cache_name] =& $this->obj[$cache_name];
                        break;

-----[заменить]-----

                    case 'db_sqlite':
                        if (!isset($this->obj[$cache_name]))
                        {
                            $cache_cfg['pconnect']     = $this->cfg['pconnect'];
                            $cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db');
                            $cache_cfg['table_name']   = $cache_name;
                            $cache_cfg['table_schema'] = $this->get_table_schema($cache_cfg);
                            $cache_cfg['file_name']    = $cache_name.'.sqlite.db';
                            $cache_cfg['dir']             = $this->cfg['db_dir'];

                            $this->obj[$cache_name] = new sqlite_common($cache_cfg);
                        }
                        $this->ref[$cache_name] =& $this->obj[$cache_name];
                        break;
                       
-----[найти]-----

class sqlite_common extends cache_common
{
    var $cfg = array(
            'db_file_path' => 'sqlite.db',
            'table_name'   => 'table_name',
            'table_schema' => 'CREATE TABLE table_name (...)',
            'pconnect'     => true,
            'con_required' => true,
            'log_name'     => 'SQLite',
            'shard_type'   => 'none',     #  none, string, int (тип перевичного ключа для шардинга)
            'shard_val'    => 0,          #  для string - кол. начальных символов, для int - делитель (будет использован остаток от деления)
        );
    var $engine    = 'SQLite';
    var $dbh       = null;
    var $connected = false;
    var $shard_val = false;

    var $table_create_attempts = 0;

    function sqlite_common ($cfg)
    {
        $this->cfg = array_merge($this->cfg, $cfg);
        $this->dbg_enabled = sql_dbg_enabled();
    }

    function connect ()
    {
        $this->cur_query = ($this->dbg_enabled) ? ($this->cfg['pconnect'] ? 'p' : '') .'connect to: '. $this->cfg['db_file_path'] : 'connect';
        $this->debug('start');

        $connect_type = ($this->cfg['pconnect']) ? 'sqlite_popen' : 'sqlite_open';

        if ($this->cfg['shard_type'] != 'none' && $this->shard_val === false)
        {
            trigger_error("cannot shard: shard_val not defined for {$this->cfg['db_file_path']}", E_USER_ERROR);
        }

        if (@$this->dbh = $connect_type($this->cfg['db_file_path'], 0666, $sqlite_error))
        {
            $this->connected = true;
        }

        if (!$this->connected && $this->cfg['con_required'])
        {
            trigger_error($sqlite_error, E_USER_ERROR);
        }

        $this->debug('stop');
        $this->cur_query = null;
    }

    function create_table ()
    {
        $this->table_create_attempts++;
        return sqlite_query($this->dbh, $this->cfg['table_schema']);
    }

    function shard ($name)
    {
        $type = $this->cfg['shard_type'];

        if ($type == 'none') return;
        if (is_array($name))  trigger_error('cannot shard: $name is array', E_USER_ERROR);

        // define shard_val
        if ($type == 'string')
        {
            $shard_val = substr($name, 0, $this->cfg['shard_val']);
        }
        else
        {
            $shard_val = $name % $this->cfg['shard_val'];
        }
        // все запросы должны быть к одному и тому же шарду
        if ($this->shard_val !== false)
        {
            if ($shard_val != $this->shard_val)
            {
                trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR);
            }
            else
            {
                return;
            }
        }
        $this->shard_val = $shard_val;
        $this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']);
    }

    function query ($query)
    {
        if (!$this->connected) $this->connect();

        $this->cur_query = $query;
        $this->debug('start');

        if (!$result = @sqlite_unbuffered_query($this->dbh, $query, SQLITE_ASSOC))
        {
            if (!$this->table_create_attempts && !sqlite_num_rows(sqlite_query($this->dbh, "PRAGMA table_info({$this->cfg['table_name']})")))
            {
                if ($this->create_table())
                {
                    $result = sqlite_unbuffered_query($this->dbh, $query, SQLITE_ASSOC);
                }
            }
            if (!$result)
            {
                $this->trigger_error($this->get_error_msg());
            }
        }

        $this->debug('stop');
        $this->cur_query = null;

        $this->num_queries++;

        return $result;
    }

    function fetch_row ($query)
    {
        $result = $this->query($query);
        return is_resource($result) ? sqlite_fetch_array($result, SQLITE_ASSOC) : false;
    }

    function fetch_rowset ($query)
    {
        $result = $this->query($query);
        return is_resource($result) ? sqlite_fetch_all($result, SQLITE_ASSOC) : array();
    }

    function changes ()
    {
        return is_resource($this->dbh) ? sqlite_changes($this->dbh) : 0;
    }

    function escape ($str)
    {
        return sqlite_escape_string($str);
    }

    function get_error_msg ()
    {
        return 'SQLite error #'. ($err_code = sqlite_last_error($this->dbh)) .': '. sqlite_error_string($err_code);
    }

    function rm ($name = '')
    {
        if ($name)
        {
            $this->db->shard($this->prefix . $name);
            $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_name = '". sqlite_escape_string($this->prefix . $name) ."'");
        }
        else
        {
            $result = $this->db->query("DELETE FROM ". $this->cfg['table_name']);
        }
        return (bool) $result;
    }

    function gc ($expire_time = TIMENOW)
    {
        $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_expire_time < $expire_time");
        return ($result) ? sqlite_changes($this->db->dbh) : 0;
    }

    function trigger_error ($msg = 'DB Error')
    {
        if (error_reporting()) trigger_error($msg, E_USER_ERROR);
    }
}

-----[заменить]-----

class sqlite_common extends cache_common
{
    var $cfg = array(
                 'db_file_path' => 'sqlite.db',
                 'table_name'   => 'table_name',
                 'table_schema' => 'CREATE TABLE table_name (...)',
                 'pconnect'     => true,
                 'con_required' => true,
                 'log_name'     => 'SQLite3',
                 'shard_type'   => 'none',     #  none, string, int (тип перевичного ключа для шардинга)
                 'shard_val'    => 0,          #  для string - кол. начальных символов, для int - делитель (будет использован остаток от деления)
                 'file_name'    => 'sqlite.db',
                 'dir'            => null,
               );
    var $engine    = 'SQLite3';
    var $dbh       = null;
    var $connected = false;
    var $shard_val = false;

    var $table_create_attempts = 0;

    function sqlite_common ($cfg)
    {
        $this->cfg = array_merge($this->cfg, $cfg);
        $this->dbg_enabled = sql_dbg_enabled();
    }

    function connect ()
    {
        $this->cur_query = ($this->dbg_enabled) ? ($this->cfg['pconnect'] ? 'p' : '') .'connect to: '. $this->cfg['db_file_path'] : 'connect';
        $this->debug('start');

        if ($this->cfg['shard_type'] != 'none' && $this->shard_val === false)
        {
            trigger_error("cannot shard: shard_val not defined for {$this->cfg['db_file_path']}", E_USER_ERROR);
        }
        $this->dbh = new SQLite3($this->cfg['db_file_path']);

        if ($this->dbh)
        {
            $this->connected = true;
        }
       
        if (!$this->connected && $this->cfg['con_required'])
        {
            trigger_error('Error', E_USER_ERROR);
        }

        $this->debug('stop');
        $this->cur_query = null;
    }

    function create_table ()
    {
        $this->table_create_attempts++;
        return $this->dbh->exec($this->cfg['table_schema']);
    }

    function shard ($name)
    {
        $type = $this->cfg['shard_type'];

        if ($type == 'none') return;
        if (is_array($name))  trigger_error('cannot shard: $name is array', E_USER_ERROR);

        // define shard_val
        if ($type == 'string')
        {
            $shard_val = substr($name, 0, $this->cfg['shard_val']);
        }
        else
        {
            $shard_val = $name % $this->cfg['shard_val'];
        }
        // все запросы должны быть к одному и тому же шарду
        if ($this->shard_val !== false)
        {
            if ($shard_val != $this->shard_val)
            {
                trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR);
            }
            else
            {
                return;
            }
        }
        $this->shard_val = $shard_val;
        $this->cfg['pconnect'] = str_replace('*', $shard_val, $this->cfg['db_file_path']);
    }

    function query ($query, $single = false)
    {
        if (!$this->connected) $this->connect();

        $this->cur_query = $query;
        $this->debug('start');
        $queryIns = ($single) ? 'querySingle':'query';
        $mode = ($single) ? @$this->dbh->$queryIns($query,true) : @$this->dbh->$queryIns($query);
        if (!$result = @$mode)
        {
            if (!$this->table_create_attempts && !$this->fetch_column_types($this->cfg['table_name']))
            {
                if ($this->create_table())
                {
                    $result = $this->dbh->exec($query);
                }
            }
        }
        $this->debug('stop');
        $this->cur_query = null;

        $this->num_queries++;

        return $result;
    }

    function fetch_row ($query)
    {
        $result = $this->query($query, true);
       
        return !empty($result) ? $result : false;
    }

    function fetch_rowset ($query)
    {
        $rows = array();
        $result = $this->query($query);
        $i = 0;
        while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
            $rows[$i]=$row;
            $i++;
        }
       
        return !empty($result) ? $rows : array();
    }
       
    function changes ()
    {
        return ($this->dbh) ? $this->dbh->changes() : 0;
    }
   
    function prepare($row)
    {
        return ($this->dbh) ? $this->dbh->prepare($row) : 0;
    }
   
    function escape ($str)
    {
        return $this->dbh->escapeString($str);
    }

    function get_error_msg ()
    {
        return 'SQLite error #'. ($err_code = $this->dbh->lastErrorMsg()) .': '. $this->dbh->lastErrorCode();
    }

    function rm ($name = '')
    {
        if ($name)
        {
            $this->db->shard($this->prefix . $name);
            $result = $this->db->exec("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_name = '". $this->dbh->prepare($this->prefix . $name) ."'");
        }
        else
        {
            $result = $this->db->exec("DELETE FROM ". $this->cfg['table_name']);
        }
        return (bool) $result;
    }

    function gc ($expire_time = TIMENOW)
    {
        $result = $this->db->exec("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_expire_time < $expire_time");
        return ($result) ? $result->changes() : 0;
    }

    function trigger_error ($msg = 'DB Error')
    {
        if (error_reporting()) trigger_error($msg, E_USER_ERROR);
    }
   
    function fetch_column_types($table_name)
    {
        $col_types = array();
        $col_info_res  = $this->dbh->query( "PRAGMA table_info('". $table_name . "')");

        while ($col_info = $col_info_res->fetchArray(SQLITE3_ASSOC))
        {
            $column_name = $col_info['name'];
            $column_type = $col_info['type'];
            $col_types[$column_name] = $column_type;
        }
        $col_info_res->finalize();
        return $col_types;
    }
}
   
####[СОХРАНИТЬ_ФАЙЛ]####

####[ОТКРЫТЬ]----- tpl_config.tpl
-----[найти]-----

$_lang = $_main . basename('lang_'. $bb_cfg['default_lang']) .'/';

-----[добавить ниже]-----

$images['icon_online']           = $_lang .'user-online.png';
$images['icon_offline']        = $_lang .'user-offline.png';
$images['icon_hidden']            = $_lang .'user-hidden.png';
   
####[СОХРАНИТЬ_ФАЙЛ]####


####[ОТКРЫТЬ]----- page_geader.tpl
-----[найти]-----

<script type="text/javascript" src="{SITE_URL}misc/js/main.js?v={$bb_cfg['js_ver']}"></script>

-----[добавить ниже]-----

<script type="text/javascript" src="{SITE_URL}misc/js/opt.js?v={$bb_cfg['js_ver']}"></script>
<link rel="stylesheet" href="{TPL_DIR}/popup.css?v={$bb_cfg['css_ver']}" type="text/css">
<link rel="stylesheet" href="{TPL_DIR}/popup-user.css?v={$bb_cfg['css_ver']}" type="text/css">
<link rel="stylesheet" href="{TPL_DIR}/AjaxPopup.css?v={$bb_cfg['css_ver']}" type="text/css">

-----[найти]-----

<body>

-----[добавить ниже]-----

<span id="user_popup"></span>

####[СОХРАНИТЬ_ФАЙЛ]####

####[ОТКРЫТЬ]----- viewtopic.tpl
-----[найти]-----

</table><!--/pagination-->
   
-----[добавить ниже]-----

<div class="category row1 border bw_TRBL mrg_8 pad_4">{WHO_ONLINE_LIST}</div>
   
####[СОХРАНИТЬ_ФАЙЛ]####
  • Снимок.webp
    Снимок.webp
    16.1 KB · Views: 198
Author
Exile
Downloads
169
Views
583
First release
Last update

Ratings

0.00 star(s) 0 ratings

More resources from Exile

Back
Top