Issues (384)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

class/NewsStory.php (68 issues)

1
<?php declare(strict_types=1);
2
3
namespace XoopsModules\News;
4
5
/*
6
 * You may not change or alter any portion of this comment or credits
7
 * of supporting developers from this source code or any supporting source code
8
 * which is considered copyrighted (c) material of the original comment or credit authors.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
 */
14
15
/**
16
 * @copyright      {@link https://xoops.org/ XOOPS Project}
17
 * @license        {@link https://www.gnu.org/licenses/gpl-2.0.html GNU GPL 2 or later}
18
 * @author         XOOPS Development Team
19
 */
20
21
use Xmf\Module\Admin;
22
23
//require_once XOOPS_ROOT_PATH . '/modules/news/class/xoopsstory.php';
24
require XOOPS_ROOT_PATH . '/include/comment_constants.php';
25
26
require_once \dirname(__DIR__) . '/preloads/autoloader.php';
27
28
/** @var Helper $helper */
29
$helper = Helper::getInstance();
30
$helper->loadLanguage('main');
31
32
/**
33
 * Class NewsStory
34
 */
35
class NewsStory extends XoopsStory
36
{
37
    public $newstopic; // XoopsTopic object
38
    public $rating; // News rating
39
    public $votes; // Number of votes
40
    public $description; // META, desciption
41
    public $keywords; // META, keywords
42
    public $picture;
43
    public $topic_imgurl;
44
    public $topic_title;
45
    public $topic_description;
46
    public $subtitle;
47
    public $pictureinfo;
48
49
    /**
50
     * Constructor
51
     * @param int $storyid
52
     */
53
    public function __construct($storyid = -1)
54
    {
55
        /** @var \XoopsMySQLDatabase $this ->db */
56
        $this->db          = \XoopsDatabaseFactory::getDatabaseConnection();
0 ignored issues
show
The property db does not seem to exist on XoopsMySQLDatabase.
Loading history...
57
        $this->table       = $this->db->prefix('news_stories');
0 ignored issues
show
The property table does not seem to exist on XoopsMySQLDatabase.
Loading history...
58
        $this->topicstable = $this->db->prefix('news_topics');
0 ignored issues
show
The property topicstable does not seem to exist on XoopsMySQLDatabase.
Loading history...
59
        if (\is_array($storyid)) {
60
            $this->makeStory($storyid);
0 ignored issues
show
The method makeStory() does not exist on XoopsMySQLDatabase. ( Ignorable by Annotation )

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

60
            $this->/** @scrutinizer ignore-call */ 
61
                   makeStory($storyid);

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...
61
        } elseif (-1 != $storyid) {
62
            $this->getStory((int)$storyid);
0 ignored issues
show
The method getStory() does not exist on XoopsMySQLDatabase. ( Ignorable by Annotation )

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

62
            $this->/** @scrutinizer ignore-call */ 
63
                   getStory((int)$storyid);

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...
63
        }
64
    }
65
66
    /**
67
     * Returns the number of stories published before a date
68
     * @param         $timestamp
69
     * @param         $expired
70
     * @param string  $topicslist
71
     * @return mixed
72
     */
73
    public function getCountStoriesPublishedBefore($timestamp, $expired, $topicslist = '')
74
    {
75
        /** @var \XoopsMySQLDatabase $db */
76
        $db  = \XoopsDatabaseFactory::getDatabaseConnection();
77
        $sql = 'SELECT count(*) AS cpt FROM ' . $db->prefix('news_stories') . ' WHERE published <=' . $timestamp;
78
        if ($expired) {
79
            $sql .= ' AND (expired>0 AND expired<=' . \time() . ')';
80
        }
81
        if ('' !== \trim($topicslist)) {
82
            $sql .= ' AND topicid IN (' . $topicslist . ')';
83
        }
84
        $result = $db->query($sql);
85
        [$count] = $db->fetchRow($result);
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchRow() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

85
        [$count] = $db->fetchRow(/** @scrutinizer ignore-type */ $result);
Loading history...
86
87
        return $count;
88
    }
89
90
    /**
91
     * Load the specified story from the database
92
     * @param $storyid
93
     */
94
    public function getStory($storyid): void
95
    {
96
        /** @var \XoopsMySQLDatabase $db */
97
        $db    = \XoopsDatabaseFactory::getDatabaseConnection();
98
        $sql   = 'SELECT s.*, t.* FROM ' . $this->table . ' s, ' . $db->prefix('news_topics') . ' t WHERE (storyid=' . (int)$storyid . ') AND (s.topicid=t.topic_id)';
99
        $array = $db->fetchArray($db->query($sql));
0 ignored issues
show
It seems like $db->query($sql) can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

99
        $array = $db->fetchArray(/** @scrutinizer ignore-type */ $db->query($sql));
Loading history...
100
        $this->makeStory($array);
101
    }
102
103
    /**
104
     * Delete stories that were published before a given date
105
     * @param         $timestamp
106
     * @param         $expired
107
     * @param string  $topicslist
108
     * @return bool
109
     */
110
    public function deleteBeforeDate($timestamp, $expired, $topicslist = '')
111
    {
112
        global $xoopsModule;
113
        /** @var \XoopsMySQLDatabase $db */
114
        $db           = \XoopsDatabaseFactory::getDatabaseConnection();
115
        $mid          = $xoopsModule->getVar('mid');
116
        $prefix       = $db->prefix('news_stories');
117
        $vote_prefix  = $db->prefix('news_stories_votedata');
118
        $files_prefix = $db->prefix('news_stories_files');
119
        $sql          = 'SELECT storyid FROM  ' . $prefix . ' WHERE published <=' . $timestamp;
120
        if ($expired) {
121
            $sql .= ' (AND expired>0 AND expired<=' . \time() . ')';
122
        }
123
        if ('' !== \trim($topicslist)) {
124
            $sql .= ' AND topicid IN (' . $topicslist . ')';
125
        }
126
        $result = $db->query($sql);
127
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

127
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
128
            \xoops_comment_delete($mid, $myrow['storyid']); // Delete comments
129
            \xoops_notification_deletebyitem($mid, 'story', $myrow['storyid']); // Delete notifications
130
            $db->queryF('DELETE FROM ' . $vote_prefix . ' WHERE storyid=' . $myrow['storyid']); // Delete votes
131
            // Remove files and records related to the files
132
            $result2 = $db->query('SELECT * FROM ' . $files_prefix . ' WHERE storyid=' . $myrow['storyid']);
133
            while (false !== ($myrow2 = $db->fetchArray($result2))) {
134
                $name = XOOPS_ROOT_PATH . '/uploads/' . $myrow2['downloadname'];
135
                if (\is_file($name)) {
136
                    \unlink($name);
137
                }
138
                $db->query('DELETE FROM ' . $files_prefix . ' WHERE fileid=' . $myrow2['fileid']);
139
            }
140
            $db->queryF('DELETE FROM ' . $prefix . ' WHERE storyid=' . $myrow['storyid']); // Delete the story
141
        }
142
143
        return true;
144
    }
145
146
    /**
147
     * @param      $storyid
148
     * @param bool $next
149
     * @param bool $checkRight
150
     *
151
     * @return array
152
     */
153
    public function _searchPreviousOrNextArticle($storyid, $next = true, $checkRight = false)
154
    {
155
        /** @var \XoopsMySQLDatabase $db */
156
        $db      = \XoopsDatabaseFactory::getDatabaseConnection();
157
        $ret     = [];
158
        $storyid = (int)$storyid;
159
        if ($next) {
160
            $sql     = 'SELECT storyid, title FROM ' . $db->prefix('news_stories') . ' WHERE (published > 0 AND published <= ' . \time() . ') AND (expired = 0 OR expired > ' . \time() . ') AND storyid > ' . $storyid;
161
            $orderBy = ' ORDER BY storyid ASC';
162
        } else {
163
            $sql     = 'SELECT storyid, title FROM ' . $db->prefix('news_stories') . ' WHERE (published > 0 AND published <= ' . \time() . ') AND (expired = 0 OR expired > ' . \time() . ') AND storyid < ' . $storyid;
164
            $orderBy = ' ORDER BY storyid DESC';
165
        }
166
        if ($checkRight) {
167
            $topics = Utility::getMyItemIds('news_view');
168
            if (\count($topics) > 0) {
169
                $sql .= ' AND topicid IN (' . \implode(',', $topics) . ')';
170
            } else {
171
                return null;
172
            }
173
        }
174
        $sql .= $orderBy;
175
176
        $result = $db->query($sql, 1);
177
        if ($result) {
178
            $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
179
            while (false !== ($row = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type true; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

179
            while (false !== ($row = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
180
                $ret = ['storyid' => $row['storyid'], 'title' => \htmlspecialchars($row['title'], \ENT_QUOTES | \ENT_HTML5)];
181
            }
182
        }
183
184
        return $ret;
185
    }
186
187
    /**
188
     * @param int  $storyid
189
     * @param bool $checkRight
190
     *
191
     * @return null|array
192
     */
193
    public function getNextArticle($storyid, $checkRight = false)
194
    {
195
        return $this->_searchPreviousOrNextArticle($storyid, true, $checkRight);
196
    }
197
198
    /**
199
     * @param      $storyid
200
     * @param bool $checkRight
201
     *
202
     * @return array
203
     */
204
    public function getPreviousArticle($storyid, $checkRight = false)
205
    {
206
        return $this->_searchPreviousOrNextArticle($storyid, false, $checkRight);
207
    }
208
209
    /**
210
     * Returns published stories according to some options
211
     * @param int    $limit
212
     * @param int    $start
213
     * @param bool   $checkRight
214
     * @param int    $topic
215
     * @param int    $ihome
216
     * @param bool   $asobject
217
     * @param string $order
218
     * @param bool   $topic_frontpage
219
     * @return array|null
220
     */
221
    public static function getAllPublished(
222
        $limit = 0,
223
        $start = 0,
224
        $checkRight = false,
225
        $topic = 0,
226
        $ihome = 0,
227
        $asobject = true,
228
        $order = 'published',
229
        $topic_frontpage = false
230
    ) {
231
        /** @var \XoopsMySQLDatabase $db */
232
        $db   = \XoopsDatabaseFactory::getDatabaseConnection();
233
        $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
234
        $ret  = [];
235
        $sql  = 'SELECT s.*, t.* FROM ' . $db->prefix('news_stories') . ' s, ' . $db->prefix('news_topics') . ' t WHERE (s.published > 0 AND s.published <= ' . \time() . ') AND (s.expired = 0 OR s.expired > ' . \time() . ') AND (s.topicid=t.topic_id) ';
236
        if (0 != $topic) {
237
            if (!\is_array($topic)) {
0 ignored issues
show
The condition is_array($topic) is always false.
Loading history...
238
                if ($checkRight) {
239
                    $topics = Utility::getMyItemIds('news_view');
240
                    if (!\in_array($topic, $topics, true)) {
241
                        return null;
242
                    }
243
                    $sql .= ' AND s.topicid=' . (int)$topic . ' AND (s.ihome=1 OR s.ihome=0)';
244
                } else {
245
                    $sql .= ' AND s.topicid=' . (int)$topic . ' AND (s.ihome=1 OR s.ihome=0)';
246
                }
247
            } else {
248
                if ($checkRight) {
249
                    $topics = Utility::getMyItemIds('news_view');
250
                    $topic  = \array_intersect($topic, $topics);
251
                }
252
                if (\count($topic) > 0) {
253
                    $sql .= ' AND s.topicid IN (' . \implode(',', $topic) . ')';
254
                } else {
255
                    return null;
256
                }
257
            }
258
        } else {
259
            if ($checkRight) {
260
                $topics = Utility::getMyItemIds('news_view');
261
                if (\count($topics) > 0) {
262
                    $topics = \implode(',', $topics);
263
                    $sql    .= ' AND s.topicid IN (' . $topics . ')';
264
                } else {
265
                    return null;
266
                }
267
            }
268
            if (0 == (int)$ihome) {
269
                $sql .= ' AND s.ihome=0';
270
            }
271
        }
272
        if ($topic_frontpage) {
273
            $sql .= ' AND t.topic_frontpage=1';
274
        }
275
        $sql    .= " ORDER BY s.$order DESC";
276
        $result = $db->query($sql, (int)$limit, (int)$start);
277
278
        if (!$db->isResultSet($result)) {
279
//            \trigger_error("Query Failed! SQL: $sql- Error: " . $db->error(), E_USER_ERROR);
280
            $helper = Helper::getInstance();
281
            $helper->redirect('/index.php', 5, $db->error());
282
        }
283
284
            while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

284
            while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
285
                if ($asobject) {
286
                    $ret[] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

286
                    $ret[] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
287
                } else {
288
                    $ret[$myrow['storyid']] = \htmlspecialchars($myrow['title'], \ENT_QUOTES | \ENT_HTML5);
289
                }
290
            }
291
292
        return $ret;
293
    }
294
295
    /**
296
     * Retourne la liste des articles aux archives (pour une p�riode donn�e)
297
     * @param             $publish_start
298
     * @param             $publish_end
299
     * @param bool        $checkRight
300
     * @param bool        $asobject
301
     * @param string      $order
302
     * @return array|null
303
     */
304
    public function getArchive(
305
        $publish_start,
306
        $publish_end,
307
        $checkRight = false,
308
        $asobject = true,
309
        $order = 'published'
310
    ) {
311
        /** @var \XoopsMySQLDatabase $db */
312
        $db   = \XoopsDatabaseFactory::getDatabaseConnection();
313
        $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
314
        $ret  = [];
315
        $sql  = 'SELECT s.*, t.* FROM ' . $db->prefix('news_stories') . ' s, ' . $db->prefix('news_topics') . ' t WHERE (s.topicid=t.topic_id) AND (s.published > ' . $publish_start . ' AND s.published <= ' . $publish_end . ') AND (expired = 0 OR expired > ' . \time() . ') ';
316
317
        if ($checkRight) {
318
            $topics = Utility::getMyItemIds('news_view');
319
            if (\count($topics) > 0) {
320
                $topics = \implode(',', $topics);
321
                $sql    .= ' AND topicid IN (' . $topics . ')';
322
            } else {
323
                return null;
324
            }
325
        }
326
        $sql    .= " ORDER BY $order DESC";
327
        $result = $db->query($sql);
328
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

328
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
329
            if ($asobject) {
330
                $ret[] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

330
                $ret[] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
331
            } else {
332
                $ret[$myrow['storyid']] = \htmlspecialchars($myrow['title'], \ENT_QUOTES | \ENT_HTML5);
333
            }
334
        }
335
336
        return $ret;
337
    }
338
339
    /**
340
     * Get the today's most readed article
341
     *
342
     * @param int    $limit      records limit
343
     * @param int    $start      starting record
344
     * @param bool   $checkRight Do we need to check permissions (by topics) ?
345
     * @param int    $topic      limit the job to one topic
346
     * @param int    $ihome      Limit to articles published in home page only ?
347
     * @param bool   $asobject   Do we have to return an array of objects or a simple array ?
348
     * @param string $order      Fields to sort on
349
     *
350
     * @return array
351
     */
352
    public function getBigStory(
353
        $limit = 0,
354
        $start = 0,
355
        $checkRight = false,
356
        $topic = 0,
357
        $ihome = 0,
358
        $asobject = true,
359
        $order = 'counter'
360
    ) {
361
        /** @var \XoopsMySQLDatabase $db */
362
        $db    = \XoopsDatabaseFactory::getDatabaseConnection();
363
        $myts  = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
364
        $ret   = [];
365
        $tdate = \mktime(0, 0, 0, (int)\date('n'), (int)\date('j'), (int)\date('Y'));
366
        $sql   = 'SELECT s.*, t.* FROM ' . $db->prefix('news_stories') . ' s, ' . $db->prefix('news_topics') . ' t WHERE (s.topicid=t.topic_id) AND (published > ' . $tdate . ' AND published < ' . \time() . ') AND (expired > ' . \time() . ' OR expired = 0) ';
367
368
        if (0 != (int)$topic) {
369
            if (!\is_array($topic)) {
0 ignored issues
show
The condition is_array($topic) is always false.
Loading history...
370
                $sql .= ' AND topicid=' . (int)$topic . ' AND (ihome=1 OR ihome=0)';
371
            } elseif (\count($topic) > 0) {
372
                $sql .= ' AND topicid IN (' . \implode(',', $topic) . ')';
373
            } else {
374
                return null;
375
            }
376
        } else {
377
            if ($checkRight) {
378
                $topics = Utility::getMyItemIds('news_view');
379
                if (\count($topics) > 0) {
380
                    $topics = \implode(',', $topics);
381
                    $sql    .= ' AND topicid IN (' . $topics . ')';
382
                } else {
383
                    return null;
384
                }
385
            }
386
            if (0 == (int)$ihome) {
387
                $sql .= ' AND ihome=0';
388
            }
389
        }
390
        $sql    .= " ORDER BY $order DESC";
391
        $result = $db->query($sql, (int)$limit, (int)$start);
392
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

392
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
393
            if ($asobject) {
394
                $ret[] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

394
                $ret[] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
395
            } else {
396
                $ret[$myrow['storyid']] = \htmlspecialchars($myrow['title'], \ENT_QUOTES | \ENT_HTML5);
397
            }
398
        }
399
400
        return $ret;
401
    }
402
403
    /**
404
     * Get all articles published by an author
405
     *
406
     * @param int  $uid        author's id
407
     * @param bool $checkRight whether to check the user's rights to topics
408
     *
409
     * @param bool $asobject
410
     *
411
     * @return array
412
     */
413
    public function getAllPublishedByAuthor($uid, $checkRight = false, $asobject = true)
414
    {
415
        /** @var \XoopsMySQLDatabase $db */
416
        $db        = \XoopsDatabaseFactory::getDatabaseConnection();
417
        $myts      = \MyTextSanitizer::getInstance();
418
        $ret       = [];
419
        $tblstory  = $db->prefix('news_stories');
420
        $tbltopics = $db->prefix('news_topics');
421
422
        $sql = 'SELECT '
423
               . $tblstory
424
               . '.*, '
425
               . $tbltopics
426
               . '.topic_title, '
427
               . $tbltopics
428
               . '.topic_color FROM '
429
               . $tblstory
430
               . ','
431
               . $tbltopics
432
               . ' WHERE ('
433
               . $tblstory
434
               . '.topicid='
435
               . $tbltopics
436
               . '.topic_id) AND (published > 0 AND published <= '
437
               . \time()
438
               . ') AND (expired = 0 OR expired > '
439
               . \time()
440
               . ')';
441
        $sql .= ' AND uid=' . (int)$uid;
442
        if ($checkRight) {
443
            $topics = Utility::getMyItemIds('news_view');
444
            $topics = \implode(',', $topics);
445
            if ('' !== \xoops_trim($topics)) {
446
                $sql .= ' AND topicid IN (' . $topics . ')';
447
            }
448
        }
449
        $sql    .= ' ORDER BY ' . $tbltopics . '.topic_title ASC, ' . $tblstory . '.published DESC';
450
        $result = $db->query($sql);
451
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

451
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
452
            if ($asobject) {
453
                $ret[] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

453
                $ret[] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
454
            } else {
455
                if ($myrow['nohtml']) {
456
                    $html = 0;
457
                } else {
458
                    $html = 1;
459
                }
460
                if ($myrow['nosmiley']) {
461
                    $smiley = 0;
462
                } else {
463
                    $smiley = 1;
464
                }
465
                $ret[$myrow['storyid']] = [
466
                    'title'       => $myts->displayTarea($myrow['title'], $html, $smiley, 1),
467
                    'topicid'     => (int)$myrow['topicid'],
468
                    'storyid'     => (int)$myrow['storyid'],
469
                    'hometext'    => $myts->displayTarea($myrow['hometext'], $html, $smiley, 1),
470
                    'counter'     => (int)$myrow['counter'],
471
                    'created'     => (int)$myrow['created'],
472
                    'topic_title' => $myts->displayTarea($myrow['topic_title'], $html, $smiley, 1),
473
                    'topic_color' => $myts->displayTarea($myrow['topic_color']),
474
                    'published'   => (int)$myrow['published'],
475
                    'rating'      => (float)$myrow['rating'],
476
                    'votes'       => (int)$myrow['votes'],
477
                ];
478
            }
479
        }
480
481
        return $ret;
482
    }
483
484
    /**
485
     * Get all expired stories
486
     * @param int  $limit
487
     * @param int  $start
488
     * @param int  $topic
489
     * @param int  $ihome
490
     * @param bool $asobject
491
     * @return array
492
     */
493
    public static function getAllExpired($limit = 0, $start = 0, $topic = 0, $ihome = 0, $asobject = true)
494
    {
495
        /** @var \XoopsMySQLDatabase $db */
496
        $db   = \XoopsDatabaseFactory::getDatabaseConnection();
497
        $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
498
        $ret  = [];
499
        $sql  = 'SELECT * FROM ' . $db->prefix('news_stories') . ' WHERE expired <= ' . \time() . ' AND expired > 0';
500
        if (!empty($topic)) {
501
            $sql .= ' AND topicid=' . (int)$topic . ' AND (ihome=1 OR ihome=0)';
502
        } elseif (0 == (int)$ihome) {
503
            $sql .= ' AND ihome=0';
504
        }
505
506
        $sql    .= ' ORDER BY expired DESC';
507
        $result = $db->query($sql, (int)$limit, (int)$start);
508
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

508
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
509
            if ($asobject) {
510
                $ret[] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

510
                $ret[] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
511
            } else {
512
                $ret[$myrow['storyid']] = \htmlspecialchars($myrow['title'], \ENT_QUOTES | \ENT_HTML5);
513
            }
514
        }
515
516
        return $ret;
517
    }
518
519
    /**
520
     * Returns an array of object containing all the news to be automatically published.
521
     * @param int  $limit
522
     * @param bool $asobject
523
     * @param int  $start
524
     * @return array
525
     */
526
    public static function getAllAutoStory($limit = 0, $asobject = true, $start = 0)
527
    {
528
        /** @var \XoopsMySQLDatabase $db */
529
        $db     = \XoopsDatabaseFactory::getDatabaseConnection();
530
        $myts   = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
531
        $ret    = [];
532
        $sql    = 'SELECT * FROM ' . $db->prefix('news_stories') . ' WHERE published > ' . \time() . ' ORDER BY published ASC';
533
        $result = $db->query($sql, (int)$limit, (int)$start);
534
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

534
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
535
            if ($asobject) {
536
                $ret[] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

536
                $ret[] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
537
            } else {
538
                $ret[$myrow['storyid']] = \htmlspecialchars($myrow['title'], \ENT_QUOTES | \ENT_HTML5);
539
            }
540
        }
541
542
        return $ret;
543
    }
544
545
    /**
546
     * Get all submitted stories awaiting approval
547
     *
548
     * @param int  $limit      Denotes where to start the query
549
     * @param bool $asobject   true will returns the stories as an array of objects, false will return storyid => title
550
     * @param bool $checkRight whether to check the user's rights to topics
551
     *
552
     * @param int  $start
553
     *
554
     * @return array
555
     */
556
    public static function getAllSubmitted($limit = 0, $asobject = true, $checkRight = false, $start = 0)
557
    {
558
        /** @var \XoopsMySQLDatabase $db */
559
        $db       = \XoopsDatabaseFactory::getDatabaseConnection();
560
        $myts     = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
561
        $ret      = [];
562
        $criteria = new \CriteriaCompo(new \Criteria('published', 0));
563
        if ($checkRight) {
564
            global $xoopsUser;
565
            if (!\is_object($xoopsUser)) {
566
                return $ret;
567
            }
568
            $allowedtopics = Utility::getMyItemIds('news_approve');
569
            $criteria2     = new \CriteriaCompo();
570
            foreach ($allowedtopics as $key => $topicid) {
571
                $criteria2->add(new \Criteria('topicid', $topicid), 'OR');
572
            }
573
            $criteria->add($criteria2);
574
        }
575
        $sql    = 'SELECT s.*, t.* FROM ' . $db->prefix('news_stories') . ' s, ' . $db->prefix('news_topics') . ' t ';
576
        $sql    .= ' ' . $criteria->renderWhere() . ' AND (s.topicid=t.topic_id) ORDER BY created DESC';
577
        $result = $db->query($sql, (int)$limit, (int)$start);
578
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

578
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
579
            if ($asobject) {
580
                $ret[] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

580
                $ret[] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
581
            } else {
582
                $ret[$myrow['storyid']] = \htmlspecialchars($myrow['title'], \ENT_QUOTES | \ENT_HTML5);
583
            }
584
        }
585
586
        return $ret;
587
    }
588
589
    /**
590
     * Used in the module's admin to know the number of expired, automated or pubilshed news
591
     *
592
     * @param int  $storytype  1=Expired, 2=Automated, 3=New submissions, 4=Last published stories
593
     * @param bool $checkRight verify permissions or not ?
594
     *
595
     * @return int
596
     */
597
    public static function getAllStoriesCount($storytype = 1, $checkRight = false)
598
    {
599
        /** @var \XoopsMySQLDatabase $db */
600
        $db  = \XoopsDatabaseFactory::getDatabaseConnection();
601
        $sql = 'SELECT count(*) AS cpt FROM ' . $db->prefix('news_stories') . ' WHERE ';
602
        switch ($storytype) {
603
            case 1: // Expired
604
                $sql .= '(expired <= ' . \time() . ' AND expired >0)';
605
                break;
606
            case 2: // Automated
607
                $sql .= '(published > ' . \time() . ')';
608
                break;
609
            case 3: // New submissions
610
                $sql .= '(published = 0)';
611
                break;
612
            case 4: // Last published stories
613
                $sql .= '(published > 0 AND published <= ' . \time() . ') AND (expired = 0 OR expired > ' . \time() . ')';
614
                break;
615
        }
616
        if ($checkRight) {
617
            $topics = Utility::getMyItemIds('news_view');
618
            if (\count($topics) > 0) {
619
                $topics = \implode(',', $topics);
620
                $sql    .= ' AND topicid IN (' . $topics . ')';
621
            } else {
622
                return 0;
623
            }
624
        }
625
        $result = $db->query($sql);
626
        $myrow  = $db->fetchArray($result);
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

626
        $myrow  = $db->fetchArray(/** @scrutinizer ignore-type */ $result);
Loading history...
627
628
        return $myrow['cpt'];
629
    }
630
631
    /**
632
     * Get a list of stories (as objects) related to a specific topic
633
     * @param        $topicid
634
     * @param int    $limit
635
     * @return array
636
     */
637
    public static function getByTopic($topicid, $limit = 0)
638
    {
639
        $ret = [];
640
        /** @var \XoopsMySQLDatabase $db */
641
        $db     = \XoopsDatabaseFactory::getDatabaseConnection();
642
        $sql    = 'SELECT * FROM ' . $db->prefix('news_stories') . ' WHERE topicid=' . (int)$topicid . ' ORDER BY published DESC';
643
        $result = $db->query($sql, (int)$limit, 0);
644
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

644
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
645
            $ret[] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

645
            $ret[] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
646
        }
647
648
        return $ret;
649
    }
650
651
    /**
652
     * Count the number of news published for a specific topic
653
     * @param int  $topicid
654
     * @param bool $checkRight
655
     * @return mixed|null
656
     */
657
    public static function countPublishedByTopic($topicid = 0, $checkRight = false)
658
    {
659
        /** @var \XoopsMySQLDatabase $db */
660
        $db  = \XoopsDatabaseFactory::getDatabaseConnection();
661
        $sql = 'SELECT COUNT(*) FROM ' . $db->prefix('news_stories') . ' WHERE published > 0 AND published <= ' . \time() . ' AND (expired = 0 OR expired > ' . \time() . ')';
662
        if (!empty($topicid)) {
663
            $sql .= ' AND topicid=' . (int)$topicid;
664
        } else {
665
            $sql .= ' AND ihome=0';
666
            if ($checkRight) {
667
                $topics = Utility::getMyItemIds('news_view');
668
                if (\count($topics) > 0) {
669
                    $topics = \implode(',', $topics);
670
                    $sql    .= ' AND topicid IN (' . $topics . ')';
671
                } else {
672
                    return null;
673
                }
674
            }
675
        }
676
        $result = $db->query($sql);
677
        [$count] = $db->fetchRow($result);
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchRow() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

677
        [$count] = $db->fetchRow(/** @scrutinizer ignore-type */ $result);
Loading history...
678
679
        return $count;
680
    }
681
682
    /**
683
     * Internal function
684
     */
685
    public function adminlink()
686
    {
687
        global $xoopsModule;
688
        $dirname = \basename(\dirname(__DIR__));
689
        /** @var \XoopsModuleHandler $moduleHandler */
690
        $moduleHandler = \xoops_getHandler('module');
691
        $module        = $moduleHandler->getByDirname($dirname);
0 ignored issues
show
The assignment to $module is dead and can be removed.
Loading history...
692
        $pathIcon16    = Admin::iconUrl('', '16');
693
694
        $ret = '&nbsp; <a href='
695
               . XOOPS_URL
696
               . '/modules/news/submit.php?op=edit&amp;storyid='
697
               . $this->storyid()
698
               . '><img src='
699
               . $pathIcon16
700
               . '/edit.png'
701
               . ' '
702
               . 'title='
703
               . \_NW_EDIT
704
               . '></a>'
705
               . '<a href='
706
               . XOOPS_URL
707
               . '/modules/news/admin/index.php?op=delete&amp;storyid='
708
               . $this->storyid()
709
               . '><img src='
710
               . $pathIcon16
711
               . '/delete.png'
712
               . ' '
713
               . 'title='
714
               . \_NW_DELETE
715
               . '></a> &nbsp;';
716
717
        return $ret;
718
    }
719
720
    /**
721
     * Get the topic image url
722
     * @param string $format
723
     * @return string
724
     */
725
    public function topic_imgurl($format = 'S')
726
    {
727
        if ('' === \trim($this->topic_imgurl)) {
728
            $this->topic_imgurl = 'blank.png';
729
        }
730
        $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
731
        switch ($format) {
732
            case 'S':
733
                $imgurl = \htmlspecialchars($this->topic_imgurl, \ENT_QUOTES | \ENT_HTML5);
734
                break;
735
            case 'E':
736
                $imgurl = \htmlspecialchars($this->topic_imgurl, \ENT_QUOTES | \ENT_HTML5);
737
                break;
738
            case 'P':
739
                $imgurl = \htmlspecialchars($this->topic_imgurl, \ENT_QUOTES | \ENT_HTML5);
740
                break;
741
            case 'F':
742
                $imgurl = \htmlspecialchars($this->topic_imgurl, \ENT_QUOTES | \ENT_HTML5);
743
                break;
744
        }
745
746
        return $imgurl;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $imgurl does not seem to be defined for all execution paths leading up to this point.
Loading history...
747
    }
748
749
    /**
750
     * @param string $format
751
     *
752
     * @return mixed
753
     */
754
    public function topic_title($format = 'S')
755
    {
756
        $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
757
        switch ($format) {
758
            case 'S':
759
                $title = \htmlspecialchars($this->topic_title, \ENT_QUOTES | \ENT_HTML5);
760
                break;
761
            case 'E':
762
                $title = \htmlspecialchars($this->topic_title, \ENT_QUOTES | \ENT_HTML5);
763
                break;
764
            case 'P':
765
                $title = $this->topic_title;
766
                $title = \htmlspecialchars($title, \ENT_QUOTES | \ENT_HTML5);
767
                break;
768
            case 'F':
769
                $title = $this->topic_title;
770
                $title = \htmlspecialchars($title, \ENT_QUOTES | \ENT_HTML5);
771
                break;
772
        }
773
774
        return $title;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $title does not seem to be defined for all execution paths leading up to this point.
Loading history...
775
    }
776
777
    /**
778
     * @return string
779
     */
780
    public function imglink()
781
    {
782
        $ret = '';
783
        if ('' !== $this->topic_imgurl()
784
            && \file_exists(XOOPS_ROOT_PATH . '/uploads/news/image/' . $this->topic_imgurl())) {
785
            $ret = '<a href="' . XOOPS_URL . '/modules/news/index.php?storytopic=' . $this->topicid() . '"><img src="' . XOOPS_URL . '/uploads/news/image/' . $this->topic_imgurl() . '" alt="' . $this->topic_title() . '" style="float: '. $this->topicalign() .'; margin: 10px; margin-top: 0px;" class="thumb_topic"></a>';
786
        }
787
788
        return $ret;
789
    }
790
791
    /**
792
     * @return string
793
     */
794
    public function textlink()
795
    {
796
        $ret = '<a title="' . $this->topic_title() . '" href="' . XOOPS_URL . '/modules/news/index.php?storytopic=' . $this->topicid() . '">' . $this->topic_title() . '</a>';
797
        return $ret;
798
    }
799
800
    /**
801
     * Function used to prepare an article to be showned
802
     * @param $filescount
803
     * @return array
804
     */
805
    public function prepare2show($filescount)
806
    {
807
        global $xoopsUser, $xoopsConfig, $xoopsModule;
808
        /** @var News\Helper $helper */
809
        $helper = Helper::getInstance();
810
811
        $dirname = \basename(\dirname(__DIR__));
812
        /** @var \XoopsModuleHandler $moduleHandler */
813
        $moduleHandler = \xoops_getHandler('module');
814
        $module        = $moduleHandler->getByDirname($dirname);
0 ignored issues
show
The assignment to $module is dead and can be removed.
Loading history...
815
        $pathIcon16    = Admin::iconUrl('', '16');
816
817
        $myts                 = \MyTextSanitizer::getInstance();
818
        $infotips             = Utility::getModuleOption('infotips');
819
        $story                = [];
820
        $story['id']          = $this->storyid();
821
        $story['poster']      = $this->uname();
822
        $story['author_name'] = $this->uname();
823
        $story['author_uid']  = $this->uid();
824
        if (false !== $story['poster']) {
0 ignored issues
show
The condition false !== $story['poster'] is always true.
Loading history...
825
            $story['poster'] = "<a href='" . XOOPS_URL . '/userinfo.php?uid=' . $this->uid() . "'>" . $story['poster'] . '</a>';
826
        } elseif (3 != $helper->getConfig('displayname')) {
827
            $story['poster'] = $xoopsConfig['anonymous'];
828
        }
829
        if ($helper->getConfig('ratenews')) {
830
            $story['rating'] = \number_format($this->rating(), 2);
831
            if (1 == $this->votes) {
832
                $story['votes'] = \_NW_ONEVOTE;
833
            } else {
834
                $story['votes'] = \sprintf(\_NW_NUMVOTES, $this->votes);
835
            }
836
        }
837
        $story['posttimestamp']     = $this->published();
838
        $story['posttime']          = \formatTimestamp($story['posttimestamp'], Utility::getModuleOption('dateformat'));
839
        $story['topic_description'] = $myts->displayTarea($this->topic_description);
840
841
        $auto_summary = '';
0 ignored issues
show
The assignment to $auto_summary is dead and can be removed.
Loading history...
842
        $tmp          = '';
843
        $auto_summary = $this->auto_summary($this->bodytext(), $tmp);
844
845
        $story['text'] = $this->hometext();
846
        $story['text'] = \str_replace('[summary]', $auto_summary, $story['text']);
847
848
        //$story['picture'] = XOOPS_URL.'/uploads/news/image/'.$this->picture();
849
        if ('' !== $this->picture()) {
850
            $story['picture'] = XOOPS_URL . '/uploads/news/image/' . $this->picture();
851
        } else {
852
            $story['picture'] = '';
853
        }
854
        $story['pictureinfo'] = $this->pictureinfo();
855
856
        $introcount = mb_strlen($story['text']);
857
        $fullcount  = mb_strlen($this->bodytext());
858
        $totalcount = $introcount + $fullcount;
859
860
        $morelink = '';
861
        if ($fullcount > 1) {
862
            $morelink .= '<a href="' . XOOPS_URL . '/modules/news/article.php?storyid=' . $this->storyid();
863
            $morelink .= '">' . _NW_READMORE . '</a>';
864
            $morelink .= ' | ' . \sprintf(_NW_BYTESMORE, $totalcount);
865
            if (\XOOPS_COMMENT_APPROVENONE != $helper->getConfig('com_rule')) {
866
                $morelink .= ' | ';
867
            }
868
        }
869
        if (\XOOPS_COMMENT_APPROVENONE != $helper->getConfig('com_rule')) {
870
            $ccount    = $this->comments();
871
            $morelink  .= '<a href="' . XOOPS_URL . '/modules/news/article.php?storyid=' . $this->storyid();
872
            $morelink2 = '<a href="' . XOOPS_URL . '/modules/news/article.php?storyid=' . $this->storyid();
873
            if (0 == $ccount) {
874
                $morelink .= '">' . _NW_COMMENTS . '</a>';
875
            } elseif ($fullcount < 1) {
876
                if (1 == $ccount) {
877
                    $morelink .= '">' . _NW_READMORE . '</a> | ' . $morelink2 . '">' . _NW_ONECOMMENT . '</a>';
878
                } else {
879
                    $morelink .= '">' . _NW_READMORE . '</a> | ' . $morelink2 . '">';
880
                    $morelink .= \sprintf(_NW_NUMCOMMENTS, $ccount);
881
                    $morelink .= '</a>';
882
                }
883
            } elseif (1 == $ccount) {
884
                $morelink .= '">' . _NW_ONECOMMENT . '</a>';
885
            } else {
886
                $morelink .= '">';
887
                $morelink .= \sprintf(_NW_NUMCOMMENTS, $ccount);
888
                $morelink .= '</a>';
889
            }
890
        }
891
        $story['morelink']  = $morelink;
892
        $story['adminlink'] = '';
893
894
        $approveprivilege = 0;
895
        if (Utility::isAdminGroup()) {
896
            $approveprivilege = 1;
897
        }
898
899
        if (1 == $helper->getConfig('authoredit')
900
            && (\is_object($xoopsUser)
901
                && $xoopsUser->getVar('uid') == $this->uid())) {
902
            $approveprivilege = 1;
903
        }
904
        if ($approveprivilege) {
905
            $story['adminlink'] = $this->adminlink();
906
        }
907
        $story['mail_link'] = 'mailto:?subject=' . \sprintf(_NW_INTARTICLE, $xoopsConfig['sitename']) . '&amp;body=' . \sprintf(_NW_INTARTFOUND, $xoopsConfig['sitename']) . ':  ' . XOOPS_URL . '/modules/news/article.php?storyid=' . $this->storyid();
908
        $story['imglink']   = '';
909
        $story['align']     = '';
910
        if ($this->topicdisplay()) {
911
            $story['imglink'] = $this->imglink();
912
            $story['align']   = $this->topicalign();
913
        }
914
        if ($infotips > 0) {
915
            $story['infotips'] = ' title="' . Utility::makeInfotips($this->hometext()) . '"';
916
        } else {
917
            $story['infotips'] = 'title="' . $this->title() . '"';
918
        }
919
        $story['title'] = "<a href='" . XOOPS_URL . '/modules/news/article.php?storyid=' . $this->storyid() . "'" . $story['infotips'] . '>' . $this->title() . '</a>';
920
        //$story['subtitle'] = $this->subtitle();
921
922
        $story['hits'] = $this->counter();
923
        if ($filescount > 0) {
924
            $story['files_attached'] = true;
925
            $story['attached_link']  = "<a href='" . XOOPS_URL . '/modules/news/article.php?storyid=' . $this->storyid() . "' title='" . _NW_ATTACHEDLIB . "'><img src=" . $pathIcon16 . '/attach.png' . ' ' . 'title=' . _NW_ATTACHEDLIB . '></a>';
926
        } else {
927
            $story['files_attached'] = false;
928
            $story['attached_link']  = '';
929
        }
930
931
        return $story;
932
    }
933
934
    /**
935
     * Returns the user's name of the current story according to the module's option "displayname"
936
     * @param int $uid
937
     * @return null|string
938
     */
939
    public function uname($uid = 0)
940
    {
941
        global $xoopsConfig;
942
        static $tblusers = [];
943
        $option = -1;
0 ignored issues
show
The assignment to $option is dead and can be removed.
Loading history...
944
        if (0 == $uid) {
945
            $uid = $this->uid();
946
        }
947
948
        if (\is_array($tblusers) && \array_key_exists($uid, $tblusers)) {
949
            return $tblusers[$uid];
950
        }
951
952
        /** @var Helper $helper */
953
        $helper = Helper::getInstance();
954
        $option = $helper->getConfig('displayname');
955
        //        $option = Utility::getModuleOption('displayname');
956
        if (!$option) {
957
            $option = 1;
958
        }
959
960
        switch ($option) {
961
            case 1: // Username
962
                $tblusers[$uid] = \XoopsUser::getUnameFromId($uid);
963
964
                return $tblusers[$uid];
965
            case 2: // Display full name (if it is not empty) /** @var \XoopsMemberHandler $memberHandler */ $memberHandler = xoops_getHandler('member');
966
                $thisuser = $memberHandler->getUser($uid);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $memberHandler seems to be never defined.
Loading history...
967
                if (\is_object($thisuser)) {
968
                    $return = $thisuser->getVar('name');
969
                    if ('' === $return) {
970
                        $return = $thisuser->getVar('uname');
971
                    }
972
                } else {
973
                    $return = $xoopsConfig['anonymous'];
974
                }
975
                $tblusers[$uid] = $return;
976
977
                return $return;
978
            case 3: // Nothing
979
                $tblusers[$uid] = '';
980
981
                return '';
982
        }
983
984
        return null;
985
    }
986
987
    /**
988
     * Function used to export news (in xml) and eventually the topics definitions
989
     * Warning, permissions are not exported !
990
     *
991
     * @param int      $fromdate     Starting date
992
     * @param int      $todate       Ending date
993
     * @param string   $topicslist
994
     * @param bool|int $usetopicsdef Should we also export topics definitions ?
995
     * @param mixed    $tbltopics
996
     * @param bool     $asobject     Return values as an object or not ?
997
     *
998
     * @param string   $order
999
     *
1000
     * @return array
1001
     * @internal param string $topiclist If not empty, a list of topics to limit to
1002
     */
1003
    public function exportNews(
1004
        $fromdate,
1005
        $todate,
1006
        $topicslist,
1007
        $usetopicsdef,
1008
        &$tbltopics,
1009
        $asobject = true,
1010
        $order = 'published'
1011
    ) {
1012
        $ret = [];
1013
        /** @var \XoopsMySQLDatabase $db */
1014
        $db   = \XoopsDatabaseFactory::getDatabaseConnection();
1015
        $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
1016
        if ($usetopicsdef) { // We firt begin by exporting topics definitions
1017
            // Before all we must know wich topics to export
1018
            $sql = 'SELECT DISTINCT topicid FROM ' . $db->prefix('news_stories') . ' WHERE (published >=' . $fromdate . ' AND published <= ' . $todate . ')';
1019
            if ('' !== \trim($topicslist)) {
1020
                $sql .= ' AND topicid IN (' . $topicslist . ')';
1021
            }
1022
            $result = $db->query($sql);
1023
            while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

1023
            while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
1024
                $tbltopics[] = $myrow['topicid'];
1025
            }
1026
        }
1027
1028
        // Now we can search for the stories
1029
        $sql = 'SELECT s.*, t.* FROM ' . $this->table . ' s, ' . $db->prefix('news_topics') . ' t WHERE (s.topicid=t.topic_id) AND (s.published >=' . $fromdate . ' AND s.published <= ' . $todate . ')';
1030
        if ('' !== \trim($topicslist)) {
1031
            $sql .= ' AND topicid IN (' . $topicslist . ')';
1032
        }
1033
        $sql    .= " ORDER BY $order DESC";
1034
        $result = $db->query($sql);
1035
        while (false !== ($myrow = $db->fetchArray($result))) {
1036
            if ($asobject) {
1037
                $ret[] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

1037
                $ret[] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
1038
            } else {
1039
                $ret[$myrow['storyid']] = \htmlspecialchars($myrow['title'], \ENT_QUOTES | \ENT_HTML5);
1040
            }
1041
        }
1042
1043
        return $ret;
1044
    }
1045
1046
    /**
1047
     * Create or update an article
1048
     * @param bool $approved
1049
     * @return bool|int
1050
     */
1051
    public function store($approved = false)
1052
    {
1053
        $myts        = \MyTextSanitizer::getInstance();
1054
        $counter     = $this->counter ?? 0;
1055
        $title       = $GLOBALS['xoopsDB']->escape($myts->censorString($this->title));
1056
        $subtitle    = $GLOBALS['xoopsDB']->escape($myts->censorString($this->subtitle));
1057
        $hostname    = $GLOBALS['xoopsDB']->escape($this->hostname);
1058
        $type        = $GLOBALS['xoopsDB']->escape($this->type);
1059
        $hometext    = $GLOBALS['xoopsDB']->escape($myts->censorString($this->hometext));
1060
        $bodytext    = $GLOBALS['xoopsDB']->escape($myts->censorString($this->bodytext));
1061
        $description = $GLOBALS['xoopsDB']->escape($myts->censorString($this->description));
1062
        $keywords    = $GLOBALS['xoopsDB']->escape($myts->censorString($this->keywords));
1063
        $picture     = $GLOBALS['xoopsDB']->escape($this->picture);
1064
        $pictureinfo = $GLOBALS['xoopsDB']->escape($myts->censorString($this->pictureinfo));
1065
        $votes       = (int)$this->votes;
1066
        $rating      = (float)$this->rating;
1067
        if (!isset($this->nohtml) || 1 != $this->nohtml) {
1068
            $this->nohtml = 0;
1069
        }
1070
        if (!isset($this->nosmiley) || 1 != $this->nosmiley) {
1071
            $this->nosmiley = 0;
1072
        }
1073
        if (!isset($this->notifypub) || 1 != $this->notifypub) {
1074
            $this->notifypub = 0;
1075
        }
1076
        if (!isset($this->topicdisplay) || 0 != $this->topicdisplay) {
1077
            $this->topicdisplay = 1;
1078
        }
1079
        $expired = !empty($this->expired) ? $this->expired : 0;
1080
        if (!isset($this->storyid)) {
1081
            //$newpost = 1;
1082
            $newstoryid = $this->db->genId($this->table . '_storyid_seq');
1083
            $created    = \time();
1084
            $published  = $this->approved ? (int)$this->published : 0;
1085
            $sql        = \sprintf(
1086
                "INSERT INTO `%s` (storyid, uid, title, created, published, expired, hostname, nohtml, nosmiley, hometext, bodytext, counter, topicid, ihome, notifypub, story_type, topicdisplay, topicalign, comments, rating, votes, description, keywords, picture, pictureinfo, subtitle) VALUES (%u, %u, '%s', %u, %u, %u, '%s', %u, %u, '%s', '%s', %u, %u, %u, %u, '%s', %u, '%s', %u, %u, %u, '%s', '%s', '%s', '%s', '%s')",
1087
                $this->table,
1088
                $newstoryid,
1089
                (int)$this->uid(),
1090
                $title,
1091
                $created,
1092
                $published,
1093
                $expired,
1094
                $hostname,
1095
                $this->nohtml(),
1096
                $this->nosmiley(),
1097
                $hometext,
1098
                $bodytext,
1099
                $counter,
1100
                (int)$this->topicid(),
1101
                $this->ihome(),
1102
                $this->notifypub(),
1103
                $type,
1104
                (int)$this->topicdisplay(),
1105
                $this->topicalign,
1106
                (int)$this->comments(),
1107
                $rating,
1108
                $votes,
1109
                $description,
1110
                $keywords,
1111
                $picture,
1112
                $pictureinfo,
1113
                $subtitle
1114
            );
1115
        } else {
1116
            $sql        = \sprintf(
1117
                "UPDATE `%s` SET title='%s', published=%u, expired=%u, nohtml=%u, nosmiley=%u, hometext='%s', bodytext='%s', topicid=%u, ihome=%u, topicdisplay=%u, topicalign='%s', comments=%u, rating=%u, votes=%u, uid=%u, description='%s', keywords='%s', picture='%s' , pictureinfo='%s' , subtitle='%s' WHERE storyid = %u",
1118
                $this->table,
1119
                $title,
1120
                (int)$this->published(),
1121
                $expired,
1122
                $this->nohtml(),
1123
                $this->nosmiley(),
1124
                $hometext,
1125
                $bodytext,
1126
                (int)$this->topicid(),
1127
                $this->ihome(),
1128
                (int)$this->topicdisplay(),
1129
                $this->topicalign,
1130
                (int)$this->comments(),
1131
                $rating,
1132
                $votes,
1133
                (int)$this->uid(),
1134
                $description,
1135
                $keywords,
1136
                $picture,
1137
                $pictureinfo,
1138
                $subtitle,
1139
                (int)$this->storyid()
1140
            );
1141
            $newstoryid = (int)$this->storyid();
1142
        }
1143
        if (!$this->db->queryF($sql)) {
1144
            return false;
1145
        }
1146
        if (empty($newstoryid)) {
1147
            $newstoryid    = $this->db->getInsertId();
1148
            $this->storyid = $newstoryid;
1149
        }
1150
1151
        return $newstoryid;
1152
    }
1153
1154
    /**
1155
     * @return mixed
1156
     */
1157
    public function picture()
1158
    {
1159
        return $this->picture;
1160
    }
1161
1162
    /**
1163
     * @return mixed
1164
     */
1165
    public function pictureinfo()
1166
    {
1167
        return $this->pictureinfo;
1168
    }
1169
1170
    /**
1171
     * @return mixed
1172
     */
1173
    public function subtitle()
1174
    {
1175
        return $this->subtitle;
1176
    }
1177
1178
    /**
1179
     * @return mixed
1180
     */
1181
    public function rating()
1182
    {
1183
        return $this->rating;
1184
    }
1185
1186
    /**
1187
     * @return mixed
1188
     */
1189
    public function votes()
1190
    {
1191
        return $this->votes;
1192
    }
1193
1194
    /**
1195
     * @param $data
1196
     */
1197
    public function setPicture($data): void
1198
    {
1199
        $this->picture = $data;
1200
    }
1201
1202
    /**
1203
     * @param $data
1204
     */
1205
    public function setPictureinfo($data): void
1206
    {
1207
        $this->pictureinfo = $data;
1208
    }
1209
1210
    /**
1211
     * @param $data
1212
     */
1213
    public function setSubtitle($data): void
1214
    {
1215
        $this->subtitle = $data;
1216
    }
1217
1218
    /**
1219
     * @param $data
1220
     */
1221
    public function setDescription($data): void
1222
    {
1223
        $this->description = $data;
1224
    }
1225
1226
    /**
1227
     * @param $data
1228
     */
1229
    public function setKeywords($data): void
1230
    {
1231
        $this->keywords = $data;
1232
    }
1233
1234
    /**
1235
     * @param string $format
1236
     *
1237
     * @return mixed
1238
     */
1239
    public function description($format = 'S')
1240
    {
1241
        $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
1242
        switch (mb_strtoupper($format)) {
1243
            case 'S':
1244
                $description = \htmlspecialchars($this->description, \ENT_QUOTES | \ENT_HTML5);
1245
                break;
1246
            case 'P':
1247
            case 'F':
1248
                $description = \htmlspecialchars($this->description, \ENT_QUOTES | \ENT_HTML5);
1249
                break;
1250
            case 'E':
1251
                $description = \htmlspecialchars($this->description, \ENT_QUOTES | \ENT_HTML5);
1252
                break;
1253
        }
1254
1255
        return $description;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $description does not seem to be defined for all execution paths leading up to this point.
Loading history...
1256
    }
1257
1258
    /**
1259
     * @param string $format
1260
     *
1261
     * @return mixed
1262
     */
1263
    public function keywords($format = 'S')
1264
    {
1265
        $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
1266
        switch (mb_strtoupper($format)) {
1267
            case 'S':
1268
                $keywords = \htmlspecialchars($this->keywords, \ENT_QUOTES | \ENT_HTML5);
1269
                break;
1270
            case 'P':
1271
            case 'F':
1272
                $keywords = \htmlspecialchars($this->keywords, \ENT_QUOTES | \ENT_HTML5);
1273
                break;
1274
            case 'E':
1275
                $keywords = \htmlspecialchars($this->keywords, \ENT_QUOTES | \ENT_HTML5);
1276
                break;
1277
        }
1278
1279
        return $keywords;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $keywords does not seem to be defined for all execution paths leading up to this point.
Loading history...
1280
    }
1281
1282
    /**
1283
     * Returns a random number of news
1284
     * @param int    $limit
1285
     * @param int    $start
1286
     * @param bool   $checkRight
1287
     * @param int    $topic
1288
     * @param int    $ihome
1289
     * @param string $order
1290
     * @param bool   $topic_frontpage
1291
     * @return array
1292
     */
1293
    public function getRandomNews(
1294
        $limit = 0,
1295
        $start = 0,
0 ignored issues
show
The parameter $start is not used and could be removed. ( Ignorable by Annotation )

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

1295
        /** @scrutinizer ignore-unused */ $start = 0,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1296
        $checkRight = false,
1297
        $topic = 0,
1298
        $ihome = 0,
1299
        $order = 'published',
1300
        $topic_frontpage = false
1301
    ) {
1302
        /** @var \XoopsMySQLDatabase $db */
1303
        $db  = \XoopsDatabaseFactory::getDatabaseConnection();
1304
        $ret = $rand_keys = $ret3 = [];
0 ignored issues
show
The assignment to $rand_keys is dead and can be removed.
Loading history...
1305
        $sql = 'SELECT storyid FROM ' . $db->prefix('news_stories') . ' WHERE (published > 0 AND published <= ' . \time() . ') AND (expired = 0 OR expired > ' . \time() . ')';
1306
        if (0 != $topic) {
1307
            if (!\is_array($topic)) {
0 ignored issues
show
The condition is_array($topic) is always false.
Loading history...
1308
                if ($checkRight) {
1309
                    $topics = Utility::getMyItemIds('news_view');
1310
                    if (!\in_array($topic, $topics, true)) {
1311
                        return null;
1312
                    }
1313
                    $sql .= ' AND topicid=' . (int)$topic . ' AND (ihome=1 OR ihome=0)';
1314
                } else {
1315
                    $sql .= ' AND topicid=' . (int)$topic . ' AND (ihome=1 OR ihome=0)';
1316
                }
1317
            } elseif (\count($topic) > 0) {
1318
                $sql .= ' AND topicid IN (' . \implode(',', $topic) . ')';
1319
            } else {
1320
                return null;
1321
            }
1322
        } else {
1323
            if ($checkRight) {
1324
                $topics = Utility::getMyItemIds('news_view');
1325
                if (\count($topics) > 0) {
1326
                    $topics = \implode(',', $topics);
1327
                    $sql    .= ' AND topicid IN (' . $topics . ')';
1328
                } else {
1329
                    return null;
1330
                }
1331
            }
1332
            if (0 == (int)$ihome) {
1333
                $sql .= ' AND ihome=0';
1334
            }
1335
        }
1336
        if ($topic_frontpage) {
1337
            $sql .= ' AND t.topic_frontpage=1';
1338
        }
1339
        $sql    .= " ORDER BY $order DESC";
1340
        $result = $db->query($sql);
1341
1342
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

1342
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
1343
            $ret[] = $myrow['storyid'];
1344
        }
1345
        $cnt = \count($ret);
1346
        if ($cnt) {
1347
            if ($limit > $cnt) {
1348
                $limit = $cnt;
1349
            }
1350
            $rand_keys = \array_rand($ret, $limit);
1351
            if ($limit > 1) {
1352
                for ($i = 0; $i < $limit; ++$i) {
1353
                    $onestory = $ret[$rand_keys[$i]];
1354
                    $ret3[]   = new self($onestory);
1355
                }
1356
            } else {
1357
                $ret3[] = new self($ret[$rand_keys]);
1358
            }
1359
        }
1360
1361
        return $ret3;
1362
    }
1363
1364
    /**
1365
     * Returns statistics about the stories and topics
1366
     * @param $limit
1367
     * @return array
1368
     */
1369
    public function getStats($limit)
1370
    {
1371
        $ret = [];
1372
        /** @var \XoopsMySQLDatabase $db */
1373
        $db   = \XoopsDatabaseFactory::getDatabaseConnection();
1374
        $tbls = $db->prefix('news_stories');
1375
        $tblt = $db->prefix('news_topics');
1376
        $tblf = $db->prefix('news_stories_files');
1377
        // Number of stories per topic, including expired and non published stories
1378
        $ret2   = [];
1379
        $sql    = "SELECT count(s.storyid) as cpt, s.topicid, t.topic_title FROM $tbls s, $tblt t WHERE s.topicid=t.topic_id GROUP BY s.topicid ORDER BY t.topic_title";
1380
        $result = $db->query($sql);
1381
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

1381
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
1382
            $ret2[$myrow['topicid']] = $myrow;
1383
        }
1384
        $ret['storiespertopic'] = $ret2;
1385
        unset($ret2);
1386
1387
        // Total of reads per topic
1388
        $ret2   = [];
1389
        $sql    = "SELECT Sum(counter) as cpt, topicid FROM $tbls GROUP BY topicid ORDER BY topicid";
1390
        $result = $db->query($sql);
1391
        while (false !== ($myrow = $db->fetchArray($result))) {
1392
            $ret2[$myrow['topicid']] = $myrow['cpt'];
1393
        }
1394
        $ret['readspertopic'] = $ret2;
1395
        unset($ret2);
1396
1397
        // Attached files per topic
1398
        $ret2   = [];
1399
        $sql    = "SELECT Count(*) as cpt, s.topicid FROM $tblf f, $tbls s WHERE f.storyid=s.storyid GROUP BY s.topicid ORDER BY s.topicid";
1400
        $result = $db->query($sql);
1401
        while (false !== ($myrow = $db->fetchArray($result))) {
1402
            $ret2[$myrow['topicid']] = $myrow['cpt'];
1403
        }
1404
        $ret['filespertopic'] = $ret2;
1405
        unset($ret2);
1406
1407
        // Expired articles per topic
1408
        $ret2   = [];
1409
        $sql    = "SELECT Count(storyid) as cpt, topicid FROM $tbls WHERE expired>0 AND expired<=" . \time() . ' GROUP BY topicid ORDER BY topicid';
1410
        $result = $db->query($sql);
1411
        while (false !== ($myrow = $db->fetchArray($result))) {
1412
            $ret2[$myrow['topicid']] = $myrow['cpt'];
1413
        }
1414
        $ret['expiredpertopic'] = $ret2;
1415
        unset($ret2);
1416
1417
        // Number of unique authors per topic
1418
        $ret2   = [];
1419
        $sql    = "SELECT Count(Distinct(uid)) as cpt, topicid FROM $tbls GROUP BY topicid ORDER BY topicid";
1420
        $result = $db->query($sql);
1421
        while (false !== ($myrow = $db->fetchArray($result))) {
1422
            $ret2[$myrow['topicid']] = $myrow['cpt'];
1423
        }
1424
        $ret['authorspertopic'] = $ret2;
1425
        unset($ret2);
1426
1427
        // Most readed articles
1428
        $ret2   = [];
1429
        $sql    = "SELECT s.storyid, s.uid, s.title, s.counter, s.topicid, t.topic_title  FROM $tbls s, $tblt t WHERE s.topicid=t.topic_id ORDER BY s.counter DESC";
1430
        $result = $db->query($sql, (int)$limit);
1431
        while (false !== ($myrow = $db->fetchArray($result))) {
1432
            $ret2[$myrow['storyid']] = $myrow;
1433
        }
1434
        $ret['mostreadednews'] = $ret2;
1435
        unset($ret2);
1436
1437
        // Less readed articles
1438
        $ret2   = [];
1439
        $sql    = "SELECT s.storyid, s.uid, s.title, s.counter, s.topicid, t.topic_title  FROM $tbls s, $tblt t WHERE s.topicid=t.topic_id ORDER BY s.counter";
1440
        $result = $db->query($sql, (int)$limit);
1441
        while (false !== ($myrow = $db->fetchArray($result))) {
1442
            $ret2[$myrow['storyid']] = $myrow;
1443
        }
1444
        $ret['lessreadednews'] = $ret2;
1445
        unset($ret2);
1446
1447
        // Best rated articles
1448
        $ret2   = [];
1449
        $sql    = "SELECT s.storyid, s.uid, s.title, s.rating, s.topicid, t.topic_title  FROM $tbls s, $tblt t WHERE s.topicid=t.topic_id ORDER BY s.rating DESC";
1450
        $result = $db->query($sql, (int)$limit);
1451
        while (false !== ($myrow = $db->fetchArray($result))) {
1452
            $ret2[$myrow['storyid']] = $myrow;
1453
        }
1454
        $ret['besratednews'] = $ret2;
1455
        unset($ret2);
1456
1457
        // Most readed authors
1458
        $ret2   = [];
1459
        $sql    = "SELECT Sum(counter) as cpt, uid FROM $tbls GROUP BY uid ORDER BY cpt DESC";
1460
        $result = $db->query($sql, (int)$limit);
1461
        while (false !== ($myrow = $db->fetchArray($result))) {
1462
            $ret2[$myrow['uid']] = $myrow['cpt'];
1463
        }
1464
        $ret['mostreadedauthors'] = $ret2;
1465
        unset($ret2);
1466
1467
        // Best rated authors
1468
        $ret2   = [];
1469
        $sql    = "SELECT Avg(rating) as cpt, uid FROM $tbls WHERE votes > 0 GROUP BY uid ORDER BY cpt DESC";
1470
        $result = $db->query($sql, (int)$limit);
1471
        while (false !== ($myrow = $db->fetchArray($result))) {
1472
            $ret2[$myrow['uid']] = $myrow['cpt'];
1473
        }
1474
        $ret['bestratedauthors'] = $ret2;
1475
        unset($ret2);
1476
1477
        // Biggest contributors
1478
        $ret2   = [];
1479
        $sql    = "SELECT Count(*) as cpt, uid FROM $tbls GROUP BY uid ORDER BY cpt DESC";
1480
        $result = $db->query($sql, (int)$limit);
1481
        while (false !== ($myrow = $db->fetchArray($result))) {
1482
            $ret2[$myrow['uid']] = $myrow['cpt'];
1483
        }
1484
        $ret['biggestcontributors'] = $ret2;
1485
        unset($ret2);
1486
1487
        return $ret;
1488
    }
1489
1490
    /**
1491
     * Get the date of the older and most recent news
1492
     * @param $older
1493
     * @param $recent
1494
     */
1495
    public function getOlderRecentNews(&$older, &$recent): void
1496
    {
1497
        /** @var \XoopsMySQLDatabase $db */
1498
        $db     = \XoopsDatabaseFactory::getDatabaseConnection();
1499
        $sql    = 'SELECT min(published) AS minpublish, max(published) AS maxpublish FROM ' . $db->prefix('news_stories');
1500
        $result = $db->query($sql);
1501
        if (!$result) {
1502
            $older = $recent = 0;
1503
        } else {
1504
            [$older, $recent] = $db->fetchRow($result);
0 ignored issues
show
Comprehensibility Best Practice introduced by
This list assign is not used and could be removed.
Loading history...
It seems like $result can also be of type true; however, parameter $result of XoopsMySQLDatabase::fetchRow() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

1504
            [$older, $recent] = $db->fetchRow(/** @scrutinizer ignore-type */ $result);
Loading history...
1505
        }
1506
    }
1507
1508
    /*
1509
     * Returns the author's IDs for the Who's who page
1510
     */
1511
1512
    /**
1513
     * @param bool $checkRight
1514
     * @param int  $limit
1515
     * @param int  $start
1516
     *
1517
     * @return array|null
1518
     */
1519
    public function getWhosWho($checkRight = false, $limit = 0, $start = 0)
0 ignored issues
show
The parameter $start is not used and could be removed. ( Ignorable by Annotation )

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

1519
    public function getWhosWho($checkRight = false, $limit = 0, /** @scrutinizer ignore-unused */ $start = 0)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $limit is not used and could be removed. ( Ignorable by Annotation )

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

1519
    public function getWhosWho($checkRight = false, /** @scrutinizer ignore-unused */ $limit = 0, $start = 0)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1520
    {
1521
        /** @var \XoopsMySQLDatabase $db */
1522
        $db  = \XoopsDatabaseFactory::getDatabaseConnection();
1523
        $ret = [];
1524
        $sql = 'SELECT DISTINCT(uid) AS uid FROM ' . $db->prefix('news_stories') . ' WHERE (published > 0 AND published <= ' . \time() . ') AND (expired = 0 OR expired > ' . \time() . ')';
1525
        if ($checkRight) {
1526
            $topics = Utility::getMyItemIds('news_view');
1527
            if (\count($topics) > 0) {
1528
                $topics = \implode(',', $topics);
1529
                $sql    .= ' AND topicid IN (' . $topics . ')';
1530
            } else {
1531
                return null;
1532
            }
1533
        }
1534
        $sql    .= ' ORDER BY uid';
1535
        $result = $db->query($sql);
1536
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

1536
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
1537
            $ret[] = $myrow['uid'];
1538
        }
1539
1540
        return $ret;
1541
    }
1542
1543
    /**
1544
     * Returns the content of the summary and the titles requires for the list selector
1545
     * @param $text
1546
     * @param $titles
1547
     * @return string
1548
     */
1549
    public function auto_summary($text, &$titles)
1550
    {
1551
        $auto_summary = '';
1552
        if (Utility::getModuleOption('enhanced_pagenav')) {
1553
            $expr_matches = [];
1554
            $posdeb       = \preg_match_all('/(\[pagebreak:|\[pagebreak).*\]/iU', $text, $expr_matches);
0 ignored issues
show
The assignment to $posdeb is dead and can be removed.
Loading history...
1555
            if (\count($expr_matches) > 0) {
1556
                $delimiters  = $expr_matches[0];
1557
                $arr_search  = ['[pagebreak:', '[pagebreak', ']'];
1558
                $arr_replace = ['', '', ''];
1559
                $cpt         = 1;
1560
                if (isset($titles) && \is_array($titles)) {
1561
                    $titles[] = \strip_tags(\sprintf(\_NW_PAGE_AUTO_SUMMARY, 1, $this->title()));
1562
                }
1563
                $item         = "<a href='" . XOOPS_URL . '/modules/news/article.php?storyid=' . $this->storyid() . "&page=0'>" . \sprintf(\_NW_PAGE_AUTO_SUMMARY, 1, $this->title()) . '</a><br>';
1564
                $auto_summary .= $item;
1565
1566
                foreach ($delimiters as $item) {
1567
                    ++$cpt;
1568
                    $item = \str_replace($arr_search, $arr_replace, $item);
1569
                    if ('' == \xoops_trim($item)) {
1570
                        $item = $cpt;
1571
                    }
1572
                    $titles[]     = \strip_tags(\sprintf(\_NW_PAGE_AUTO_SUMMARY, $cpt, $item));
1573
                    $item         = "<a href='" . XOOPS_URL . '/modules/news/article.php?storyid=' . $this->storyid() . '&page=' . ($cpt - 1) . "'>" . \sprintf(\_NW_PAGE_AUTO_SUMMARY, $cpt, $item) . '</a><br>';
1574
                    $auto_summary .= $item;
1575
                }
1576
            }
1577
        }
1578
1579
        return $auto_summary;
1580
    }
1581
1582
    /**
1583
     * @param string $format
1584
     *
1585
     * @return mixed
1586
     */
1587
    public function hometext($format = 'Show')
1588
    {
1589
        $hometext = '';
1590
        $myts     = \MyTextSanitizer::getInstance();
1591
        $html     = $smiley = $xcodes = 1;
1592
        if ($this->nohtml()) {
1593
            $html = 0;
1594
        }
1595
        if ($this->nosmiley()) {
1596
            $smiley = 0;
1597
        }
1598
        switch ($format) {
1599
            case 'Show':
1600
                $hometext     = $myts->displayTarea($this->hometext, $html, $smiley, $xcodes);
1601
                $tmp          = '';
1602
                $auto_summary = $this->auto_summary($this->bodytext('Show'), $tmp);
1603
                $hometext     = \str_replace('[summary]', $auto_summary, $hometext);
1604
                break;
1605
            case 'Edit':
1606
                $hometext = \htmlspecialchars($this->hometext, \ENT_QUOTES | \ENT_HTML5);
1607
                break;
1608
            case 'Preview':
1609
                $hometext = $myts->previewTarea($this->hometext, $html, $smiley, $xcodes);
1610
                break;
1611
            case 'InForm':
1612
                $hometext = \htmlspecialchars($this->hometext, \ENT_QUOTES | \ENT_HTML5);
1613
                break;
1614
        }
1615
1616
        return $hometext;
1617
    }
1618
1619
    /**
1620
     * @param string $format
1621
     *
1622
     * @return mixed
1623
     */
1624
    public function bodytext($format = 'Show')
1625
    {
1626
        $myts   = \MyTextSanitizer::getInstance();
1627
        $html   = 1;
1628
        $smiley = 1;
1629
        $xcodes = 1;
1630
        if ($this->nohtml()) {
1631
            $html = 0;
1632
        }
1633
        if ($this->nosmiley()) {
1634
            $smiley = 0;
1635
        }
1636
        switch ($format) {
1637
            case 'Show':
1638
                $bodytext     = $myts->displayTarea($this->bodytext, $html, $smiley, $xcodes);
1639
                $tmp          = '';
1640
                $auto_summary = $this->auto_summary($bodytext, $tmp);
1641
                $bodytext     = \str_replace('[summary]', $auto_summary, $bodytext);
1642
                break;
1643
            case 'Edit':
1644
                $bodytext = \htmlspecialchars($this->bodytext, \ENT_QUOTES | \ENT_HTML5);
1645
                break;
1646
            case 'Preview':
1647
                $bodytext = $myts->previewTarea($this->bodytext, $html, $smiley, $xcodes);
1648
                break;
1649
            case 'InForm':
1650
                $bodytext = \htmlspecialchars($this->bodytext, \ENT_QUOTES | \ENT_HTML5);
1651
                break;
1652
        }
1653
1654
        return $bodytext;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $bodytext does not seem to be defined for all execution paths leading up to this point.
Loading history...
1655
    }
1656
1657
    /**
1658
     * Returns stories by Ids
1659
     * @param             $ids
1660
     * @param bool        $checkRight
1661
     * @param bool        $asobject
1662
     * @param string      $order
1663
     * @param bool        $onlyOnline
1664
     * @return array|null
1665
     */
1666
    public function getStoriesByIds(
1667
        $ids,
1668
        $checkRight = true,
1669
        $asobject = true,
1670
        $order = 'published',
1671
        $onlyOnline = true
1672
    ) {
1673
        $limit = $start = 0;
1674
        /** @var \XoopsMySQLDatabase $db */
1675
        $db   = \XoopsDatabaseFactory::getDatabaseConnection();
1676
        $myts = \MyTextSanitizer::getInstance();
0 ignored issues
show
The assignment to $myts is dead and can be removed.
Loading history...
1677
        $ret  = [];
1678
        $sql  = 'SELECT s.*, t.* FROM ' . $db->prefix('news_stories') . ' s, ' . $db->prefix('news_topics') . ' t WHERE ';
1679
        if ($ids && \is_array($ids)) {
1680
            \array_walk($ids, '\intval');
1681
        }
1682
        $sql .= ' s.storyid IN (' . \implode(',', $ids) . ') ';
1683
1684
        if ($onlyOnline) {
1685
            $sql .= ' AND (s.published > 0 AND s.published <= ' . \time() . ') AND (s.expired = 0 OR s.expired > ' . \time() . ') ';
1686
        }
1687
        $sql .= ' AND (s.topicid=t.topic_id) ';
1688
        if ($checkRight) {
1689
            $topics = Utility::getMyItemIds('news_view');
1690
            if (\count($topics) > 0) {
1691
                $topics = \implode(',', $topics);
1692
                $sql    .= ' AND s.topicid IN (' . $topics . ')';
1693
            } else {
1694
                return null;
1695
            }
1696
        }
1697
        $sql    .= " ORDER BY s.$order DESC";
1698
        $result = $db->query($sql, $limit, $start);
1699
1700
        while (false !== ($myrow = $db->fetchArray($result))) {
0 ignored issues
show
It seems like $result can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

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

1700
        while (false !== ($myrow = $db->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
1701
            if ($asobject) {
1702
                $ret[$myrow['storyid']] = new self($myrow);
0 ignored issues
show
$myrow of type array is incompatible with the type integer expected by parameter $storyid of XoopsModules\News\NewsStory::__construct(). ( Ignorable by Annotation )

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

1702
                $ret[$myrow['storyid']] = new self(/** @scrutinizer ignore-type */ $myrow);
Loading history...
1703
            } else {
1704
                $ret[$myrow['storyid']] = \htmlspecialchars($myrow['title'], \ENT_QUOTES | \ENT_HTML5);
1705
            }
1706
        }
1707
1708
        return $ret;
1709
    }
1710
}
1711