OnlineHandler::init()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 6
nop 2
dl 0
loc 19
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
namespace XoopsModules\Newbb;
4
5
/**
6
 * NewBB 5.0x,  the forum module for XOOPS project
7
 *
8
 * @copyright      XOOPS Project (https://xoops.org)
9
 * @license        GNU GPL 2 or later (https://www.gnu.org/licenses/gpl-2.0.html)
10
 * @author         Taiwen Jiang (phppp or D.J.) <[email protected]>
11
 * @since          4.00
12
 * @package        module::newbb
13
 */
14
15
use Xmf\IPAddress;
16
use XoopsModules\Newbb;
17
18
19
20
require_once \dirname(__DIR__) . '/include/functions.config.php';
21
22
/**
23
 * Class OnlineHandler
24
 */
25
class OnlineHandler
26
{
27
    public $db;
28
    public $forum_id;
29
    public $forumObject;
30
    public $topic_id;
31
    public $user_ids = [];
32
33
    /**
34
     * OnlineHandler constructor.
35
     * @param \XoopsDatabase|null $db
36
     */
37
    public function __construct(\XoopsDatabase $db = null)
38
    {
39
        $this->db = $db;
40
    }
41
42
    /**
43
     * @param null|Newbb\Forum $forum
44
     * @param null|Topic       $forumtopic
45
     */
46
    public function init($forum = null, $forumtopic = null)
47
    {
48
        if (\is_object($forum)) {
49
            $this->forum_id    = $forum->getVar('forum_id');
50
            $this->forumObject = $forum;
51
        } else {
52
            $this->forum_id    = (int)$forum;
53
            $this->forumObject = $forum;
54
        }
55
        if (\is_object($forumtopic)) {
56
            $this->topic_id = $forumtopic->getVar('topic_id');
57
            if (empty($this->forum_id)) {
58
                $this->forum_id = $forumtopic->getVar('forum_id');
59
            }
60
        } else {
61
            $this->topic_id = (int)$forumtopic;
62
        }
63
64
        $this->update();
65
    }
66
67
    public function update()
68
    {
69
        global $xoopsModule;
70
71
        // set gc probabillity to 10% for now..
72
        if (\mt_rand(1, 100) < 60) {
73
            $this->gc(150);
74
        }
75
        if (\is_object($GLOBALS['xoopsUser'])) {
76
            $uid   = $GLOBALS['xoopsUser']->getVar('uid');
77
            $uname = $GLOBALS['xoopsUser']->getVar('uname');
78
            $name  = $GLOBALS['xoopsUser']->getVar('name');
79
        } else {
80
            $uid   = 0;
81
            $uname = '';
82
            $name  = '';
83
        }
84
85
        $xoops_onlineHandler = \xoops_getHandler('online');
86
        $xoopsupdate         = $xoops_onlineHandler->write($uid, $uname, \time(), $xoopsModule->getVar('mid'), \Xmf\IPAddress::fromRequest()->asReadable());
0 ignored issues
show
Bug introduced by
The method write() does not exist on XoopsObjectHandler. It seems like you code against a sub-type of XoopsObjectHandler such as XoopsPersistableObjectHandler. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

86
        /** @scrutinizer ignore-call */ 
87
        $xoopsupdate         = $xoops_onlineHandler->write($uid, $uname, \time(), $xoopsModule->getVar('mid'), \Xmf\IPAddress::fromRequest()->asReadable());
Loading history...
87
        if (!$xoopsupdate) {
88
            //xoops_error("newbb online upate error");
89
        }
90
91
        $uname = (empty($GLOBALS['xoopsModuleConfig']['show_realname']) || empty($name)) ? $uname : $name;
92
        $this->write($uid, $uname, \time(), $this->forum_id, IPAddress::fromRequest()->asReadable(), $this->topic_id);
93
    }
94
95
    /**
96
     * @param $xoopsTpl
97
     */
98
    public function render(\Smarty $xoopsTpl)
99
    {
100
        require_once \dirname(__DIR__) . '/include/functions.render.php';
101
        require_once \dirname(__DIR__) . '/include/functions.user.php';
102
        $criteria = null;
103
        if ($this->topic_id) {
104
            $criteria = new \Criteria('online_topic', $this->topic_id);
105
        } elseif ($this->forum_id) {
106
            $criteria = new \Criteria('online_forum', $this->forum_id);
107
        }
108
        $users     = $this->getAll($criteria);
109
        $num_total = \count($users);
110
111
        $num_user     = 0;
112
        $users_id     = [];
113
        $users_online = [];
114
        for ($i = 0; $i < $num_total; ++$i) {
115
            if (empty($users[$i]['online_uid'])) {
116
                continue;
117
            }
118
            $users_id[]                             = $users[$i]['online_uid'];
119
            $users_online[$users[$i]['online_uid']] = [
120
                'link'  => XOOPS_URL . '/userinfo.php?uid=' . $users[$i]['online_uid'],
121
                'uname' => $users[$i]['online_uname'],
122
            ];
123
            ++$num_user;
124
        }
125
        $num_anonymous           = $num_total - $num_user;
126
        $online                  = [];
127
        $online['image']         = \newbbDisplayImage('whosonline');
128
        $online['num_total']     = $num_total;
129
        $online['num_user']      = $num_user;
130
        $online['num_anonymous'] = $num_anonymous;
131
        $administrator_list      = \newbbIsModuleAdministrators($users_id);
132
        $moderator_list          = [];
133
        $member_list             = \array_diff(\array_keys($administrator_list), $users_id);
134
        if ($member_list) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $member_list of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
135
            if (\is_object($this->forumObject)) {
136
                $moderator_list = $this->forumObject->getVar('forum_moderator');
137
            } else {
138
                $moderator_list = \newbbIsForumModerators($member_list);
139
            }
140
        }
141
        foreach ($users_online as $uid => $user) {
142
            if (!empty($administrator_list[$uid])) {
143
                $user['level'] = 2;
144
            } elseif (!empty($moderator_list[$uid])) {
145
                $user['level'] = 1;
146
            } else {
147
                $user['level'] = 0;
148
            }
149
            $online['users'][] = $user;
150
        }
151
152
        $xoopsTpl->assign_by_ref('online', $online);
153
    }
154
155
    /**
156
     * Deprecated
157
     */
158
    public function showOnline()
159
    {
160
        require_once \dirname(__DIR__) . '/include/functions.render.php';
161
        require_once \dirname(__DIR__) . '/include/functions.user.php';
162
        $criteria = null;
163
        if ($this->topic_id) {
164
            $criteria = new \Criteria('online_topic', $this->topic_id);
165
        } elseif ($this->forum_id) {
166
            $criteria = new \Criteria('online_forum', $this->forum_id);
167
        }
168
        $users     = $this->getAll($criteria);
169
        $num_total = \count($users);
170
171
        $num_user     = 0;
172
        $users_id     = [];
173
        $users_online = [];
174
        for ($i = 0; $i < $num_total; ++$i) {
175
            if (empty($users[$i]['online_uid'])) {
176
                continue;
177
            }
178
            $users_id[]                             = $users[$i]['online_uid'];
179
            $users_online[$users[$i]['online_uid']] = [
180
                'link'  => XOOPS_URL . '/userinfo.php?uid=' . $users[$i]['online_uid'],
181
                'uname' => $users[$i]['online_uname'],
182
            ];
183
            ++$num_user;
184
        }
185
        $num_anonymous           = $num_total - $num_user;
186
        $online                  = [];
187
        $online['image']         = \newbbDisplayImage('whosonline');
188
        $online['statistik']     = \newbbDisplayImage('statistik');
189
        $online['num_total']     = $num_total;
190
        $online['num_user']      = $num_user;
191
        $online['num_anonymous'] = $num_anonymous;
192
        $administrator_list      = \newbbIsModuleAdministrators($users_id);
193
        $moderator_list          = [];
194
        $member_list             = \array_diff($users_id, \array_keys($administrator_list));
195
        if ($member_list) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $member_list of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
196
            if (\is_object($this->forumObject)) {
197
                $moderator_list = $this->forumObject->getVar('forum_moderator');
198
            } else {
199
                $moderator_list = \newbbIsForumModerators($member_list);
200
            }
201
        }
202
203
        foreach ($users_online as $uid => $user) {
204
            if (\in_array($uid, $administrator_list)) {
205
                $user['level'] = 2;
206
            } elseif (\in_array($uid, $moderator_list)) {
207
                $user['level'] = 1;
208
            } else {
209
                $user['level'] = 0;
210
            }
211
            $online['users'][] = $user;
212
        }
213
214
        return $online;
215
    }
216
217
    /**
218
     * Write online information to the database
219
     *
220
     * @param int     $uid      UID of the active user
221
     * @param string  $uname    Username
222
     * @param         $time
223
     * @param string  $forum_id Current forum_id
224
     * @param string  $ip       User's IP adress
225
     * @param         $topic_id
226
     * @return bool   TRUE on success
227
     * @internal param string $timestamp
228
     */
229
    public function write($uid, $uname, $time, $forum_id, $ip, $topic_id)
230
    {
231
        global $xoopsModule, $xoopsDB;
232
233
        $uid = (int)$uid;
234
        if ($uid > 0) {
235
            $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('newbb_online') . ' WHERE online_uid=' . $uid;
0 ignored issues
show
Bug introduced by
The method prefix() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

235
            $sql = 'SELECT COUNT(*) FROM ' . $this->db->/** @scrutinizer ignore-call */ prefix('newbb_online') . ' WHERE online_uid=' . $uid;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
236
        } else {
237
            $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('newbb_online') . ' WHERE online_uid=' . $uid . " AND online_ip='" . $ip . "'";
238
        }
239
        [$count] = $this->db->fetchRow($this->db->queryF($sql));
240
        if ($count > 0) {
241
            $sql = 'UPDATE ' . $this->db->prefix('newbb_online') . " SET online_updated= '" . $time . "', online_forum = '" . $forum_id . "', online_topic = '" . $topic_id . "' WHERE online_uid = " . $uid;
242
            if (0 == $uid) {
243
                $sql .= " AND online_ip='" . $ip . "'";
244
            }
245
        } else {
246
            $sql = \sprintf('INSERT INTO `%s` (online_uid, online_uname, online_updated, online_ip, online_forum, online_topic) VALUES (%u, %s, %u, %s, %u, %u)', $this->db->prefix('newbb_online'), $uid, $this->db->quote($uname), $time, $this->db->quote($ip), $forum_id, $topic_id);
247
        }
248
        if (!$this->db->queryF($sql)) {
249
            //xoops_error($this->db->error());
250
            return false;
251
        }
252
253
        /** @var \XoopsOnlineHandler $xoops_onlineHandler */
254
        $xoops_onlineHandler = \xoops_getHandler('online');
255
        $xoopsOnlineTable    = $xoops_onlineHandler->table;
256
257
        $sql = 'DELETE FROM '
258
               . $this->db->prefix('newbb_online')
259
               . ' WHERE'
260
               . ' ( online_uid > 0 AND online_uid NOT IN ( SELECT online_uid FROM '
261
               . $xoopsOnlineTable
262
               . ' WHERE online_module ='
263
               . $xoopsModule->getVar('mid')
264
               . ' ) )'
265
               . ' OR ( online_uid = 0 AND online_ip NOT IN ( SELECT online_ip FROM '
266
               . $xoopsOnlineTable
267
               . ' WHERE online_module ='
268
               . $xoopsModule->getVar('mid')
269
               . ' AND online_uid = 0 ) )';
270
271
        $result = $this->db->queryF($sql);
272
        if ($result) {
273
            return true;
274
        }
275
        //xoops_error($this->db->error());
276
        return false;
277
    }
278
279
    /**
280
     * Garbage Collection
281
     *
282
     * Delete all online information that has not been updated for a certain time
283
     *
284
     * @param int $expire Expiration time in seconds
285
     */
286
    public function gc($expire)
287
    {
288
        global $xoopsModule;
289
        $sql = 'DELETE FROM ' . $this->db->prefix('newbb_online') . ' WHERE online_updated < ' . (\time() - (int)$expire);
290
        $this->db->queryF($sql);
291
292
        $xoops_onlineHandler = \xoops_getHandler('online');
293
        $xoops_onlineHandler->gc($expire);
0 ignored issues
show
Bug introduced by
The method gc() does not exist on XoopsObjectHandler. It seems like you code against a sub-type of XoopsObjectHandler such as XoopsPersistableObjectHandler. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

293
        $xoops_onlineHandler->/** @scrutinizer ignore-call */ 
294
                              gc($expire);
Loading history...
294
    }
295
296
    /**
297
     * Get an array of online information
298
     *
299
     * @param \CriteriaElement $criteria {@link \CriteriaElement}
300
     * @return array           Array of associative arrays of online information
301
     */
302
    public function getAll(\CriteriaElement $criteria = null)
303
    {
304
        $ret   = [];
305
        $limit = $start = 0;
306
        $sql   = 'SELECT * FROM ' . $this->db->prefix('newbb_online');
307
        if (\is_object($criteria) && $criteria instanceof \CriteriaElement) {
308
            $sql   .= ' ' . $criteria->renderWhere();
0 ignored issues
show
Bug introduced by
The method renderWhere() does not exist on CriteriaElement. Did you maybe mean render()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

308
            $sql   .= ' ' . $criteria->/** @scrutinizer ignore-call */ renderWhere();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
309
            $limit = $criteria->getLimit();
310
            $start = $criteria->getStart();
311
        }
312
        $result = $this->db->query($sql, $limit, $start);
313
        if (!$result) {
314
            return $ret;
315
        }
316
        while (false !== ($myrow = $this->db->fetchArray($result))) {
317
            $ret[] = $myrow;
318
            if ($myrow['online_uid'] > 0) {
319
                $this->user_ids[] = $myrow['online_uid'];
320
            }
321
            unset($myrow);
322
        }
323
        $this->user_ids = \array_unique($this->user_ids);
324
325
        return $ret;
326
    }
327
328
    /**
329
     * @param $uids
330
     * @return array
331
     */
332
    public function checkStatus($uids)
333
    {
334
        $online_users = [];
335
        $ret          = [];
336
        if (!empty($this->user_ids)) {
337
            $online_users = $this->user_ids;
338
        } else {
339
            $sql = 'SELECT online_uid FROM ' . $this->db->prefix('newbb_online');
340
            if (!empty($uids)) {
341
                $sql .= ' WHERE online_uid IN (' . \implode(', ', \array_map('\intval', $uids)) . ')';
342
            }
343
344
            $result = $this->db->query($sql);
345
            if (!$result) {
346
                return $ret;
347
            }
348
            while (list($uid) = $this->db->fetchRow($result)) {
349
                $online_users[] = $uid;
350
            }
351
        }
352
        foreach ($uids as $uid) {
353
            if (\in_array($uid, $online_users)) {
354
                $ret[$uid] = 1;
355
            }
356
        }
357
358
        return $ret;
359
    }
360
361
    /**
362
     * Count the number of online users
363
     *
364
     * @param \CriteriaElement $criteria {@link CriteriaElement}
365
     * @return bool
366
     */
367
    public function getCount(\CriteriaElement $criteria = null)
368
    {
369
        $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('newbb_online');
370
        if (\is_object($criteria) && $criteria instanceof \CriteriaElement) {
371
            $sql .= ' ' . $criteria->renderWhere();
372
        }
373
        if (!$result = $this->db->query($sql)) {
374
            return false;
375
        }
376
        [$ret] = $this->db->fetchRow($result);
377
378
        return $ret;
379
    }
380
}
381