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.

include/functions.php (1 issue)

1
<?php declare(strict_types=1);
2
/*
3
 * You may not change or alter any portion of this comment or credits
4
 * of supporting developers from this source code or any supporting source code
5
 * which is considered copyrighted (c) material of the original comment or credit authors.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 */
11
12
/**
13
 * @copyright      {@link https://xoops.org/ XOOPS Project}
14
 * @license        {@link https://www.gnu.org/licenses/gpl-2.0.html GNU GPL 2 or later}
15
 * @author         XOOPS Development Team
16
 * @author         Hervé Thouzard (https://www.herve-thouzard.com)
17
 */
18
19
/**
20
 * Returns a module's option
21
 *
22
 * Return's a module's option (for the news module)
23
 *
24
 * @param string $option module option's name
25
 *
26
 * @param string $repmodule
27
 *
28
 * @return bool
29
 */
30
31
use WideImage\WideImage;
32
use Xmf\Request;
33
use XoopsModules\News;
34
use XoopsModules\News\Blacklist;
35
use XoopsModules\News\NewsTopic;
36
use XoopsModules\News\Registryfile;
37
38
/**
39
 * @param             $option
40
 * @param string      $repmodule
41
 * @return bool|mixed
42
 */
43
function news_getmoduleoption($option, $repmodule = 'news')
44
{
45
    global $xoopsModuleConfig, $xoopsModule;
46
    static $tbloptions = [];
47
    if (is_array($tbloptions) && array_key_exists($option, $tbloptions)) {
48
        return $tbloptions[$option];
49
    }
50
51
    $retval = false;
52
    if (isset($xoopsModuleConfig)
53
        && (is_object($xoopsModule) && $xoopsModule->getVar('dirname') == $repmodule
54
            && $xoopsModule->getVar('isactive'))) {
55
        if (isset($xoopsModuleConfig[$option])) {
56
            $retval = $xoopsModuleConfig[$option];
57
        }
58
    } else {
59
        /** @var \XoopsModuleHandler $moduleHandler */
60
        $moduleHandler = xoops_getHandler('module');
61
        $module        = $moduleHandler->getByDirname($repmodule);
62
        /** @var \XoopsConfigHandler $configHandler */
63
        $configHandler = xoops_getHandler('config');
64
        if ($module) {
65
            $moduleConfig = $configHandler->getConfigsByCat(0, $module->getVar('mid'));
66
            if (isset($moduleConfig[$option])) {
67
                $retval = $moduleConfig[$option];
68
            }
69
        }
70
    }
71
    $tbloptions[$option] = $retval;
72
73
    return $retval;
74
}
75
76
/**
77
 * Updates rating data in item table for a given item
78
 *
79
 * @param $storyid
80
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
81
 * @copyright (c) Hervé Thouzard
82
 */
83
function news_updaterating($storyid): void
84
{
85
    global $xoopsDB;
86
    $query       = 'SELECT rating FROM ' . $xoopsDB->prefix('news_stories_votedata') . ' WHERE storyid = ' . $storyid;
87
    $voteresult  = $xoopsDB->query($query);
88
    $votesDB     = $xoopsDB->getRowsNum($voteresult);
89
    $totalrating = 0;
90
    while ([$rating] = $xoopsDB->fetchRow($voteresult)) {
91
        $totalrating += $rating;
92
    }
93
    $finalrating = $totalrating / $votesDB;
94
    $finalrating = number_format($finalrating, 4);
95
    $sql         = sprintf('UPDATE `%s` SET rating = %u, votes = %u WHERE storyid = %u', $xoopsDB->prefix('news_stories'), $finalrating, $votesDB, $storyid);
96
    $xoopsDB->queryF($sql);
97
}
98
99
/**
100
 * Internal function for permissions
101
 *
102
 * Returns a list of all the permitted topics Ids for the current user
103
 *
104
 * @param string $permtype
105
 *
106
 * @return array    Permitted topics Ids
107
 *
108
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
109
 * @copyright (c) Hervé Thouzard
110
 */
111
function news_MygetItemIds($permtype = 'news_view')
112
{
113
    global $xoopsUser;
114
    static $tblperms = [];
115
    if (is_array($tblperms) && array_key_exists($permtype, $tblperms)) {
116
        return $tblperms[$permtype];
117
    }
118
119
    /** @var \XoopsModuleHandler $moduleHandler */
120
    $moduleHandler = xoops_getHandler('module');
121
    $newsModule    = $moduleHandler->getByDirname('news');
122
    $groups        = is_object($xoopsUser) ? $xoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;
123
    /** @var \XoopsGroupPermHandler $grouppermHandler */
124
    $grouppermHandler    = xoops_getHandler('groupperm');
125
    $topics              = $grouppermHandler->getItemIds($permtype, $groups, $newsModule->getVar('mid'));
126
    $tblperms[$permtype] = $topics;
127
128
    return $topics;
129
}
130
131
/**
132
 * @param $document
133
 *
134
 * @return mixed
135
 */
136
function news_html2text($document)
137
{
138
    // PHP Manual:: function preg_replace
139
    // $document should contain an HTML document.
140
    // This will remove HTML tags, javascript sections
141
    // and white space. It will also convert some
142
    // common HTML entities to their text equivalent.
143
144
    $search = [
145
        "'<script[^>]*?>.*?</script>'si", // Strip out javascript
146
        "'<img.*?>'si", // Strip out img tags
147
        "'<[\/\!]*?[^<>]*?>'si", // Strip out HTML tags
148
        "'([\r\n])[\s]+'", // Strip out white space
149
        "'&(quot|#34);'i", // Replace HTML entities
150
        "'&(amp|#38);'i",
151
        "'&(lt|#60);'i",
152
        "'&(gt|#62);'i",
153
        "'&(nbsp|#160);'i",
154
        "'&(iexcl|#161);'i",
155
        "'&(cent|#162);'i",
156
        "'&(pound|#163);'i",
157
        "'&(copy|#169);'i",
158
    ]; // evaluate as php
159
160
    $replace = [
161
        '',
162
        '',
163
        '',
164
        '\\1',
165
        '"',
166
        '&',
167
        '<',
168
        '>',
169
        ' ',
170
        chr(161),
171
        chr(162),
172
        chr(163),
173
        chr(169),
174
    ];
175
176
    $text = preg_replace($search, $replace, $document);
177
178
    preg_replace_callback(
179
        '/&#(\d+);/',
180
        static function ($matches) {
181
            return chr($matches[1]);
182
        },
183
        $document
184
    );
185
186
    return $text;
187
}
188
189
/**
190
 * Is Xoops 2.3.x ?
191
 *
192
 * @return bool need to say it ?
193
 */
194
function news_isX23()
195
{
196
    $x23 = false;
197
    $xv  = str_replace('XOOPS ', '', XOOPS_VERSION);
198
    if (mb_substr($xv, 2, 1) >= '3') {
199
        $x23 = true;
200
    }
201
202
    return $x23;
203
}
204
205
/**
206
 * Retrieve an editor according to the module's option "form_options"
207
 *
208
 * @param                                                                                                                                 $caption
209
 * @param                                                                                                                                 $name
210
 * @param string                                                                                                                          $value
211
 * @param string                                                                                                                          $width
212
 * @param string                                                                                                                          $height
213
 * @param string                                                                                                                          $supplemental
214
 * @return bool|XoopsFormDhtmlTextArea|XoopsFormEditor|\XoopsFormFckeditor|\XoopsFormHtmlarea|\XoopsFormTextArea|\XoopsFormTinyeditorTextArea
215
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
216
 * @copyright (c) Hervé Thouzard
217
 */
218
function news_getWysiwygForm($caption, $name, $value = '', $width = '100%', $height = '400px', $supplemental = '')
219
{
220
    $editor_option            = \mb_strtolower(news_getmoduleoption('form_options'));
221
    $editor                   = false;
222
    $editor_configs           = [];
223
    $editor_configs['name']   = $name;
224
    $editor_configs['value']  = $value;
225
    $editor_configs['rows']   = 35;
226
    $editor_configs['cols']   = 60;
227
    $editor_configs['width']  = '100%';
228
    $editor_configs['height'] = '350px';
229
    $editor_configs['editor'] = $editor_option;
230
231
    if (news_isX23()) {
232
        $editor = new \XoopsFormEditor($caption, $name, $editor_configs);
233
234
        return $editor;
235
    }
236
237
    // Only for Xoops 2.0.x
238
    switch ($editor_option) {
239
        case 'fckeditor':
240
            if (is_readable(XOOPS_ROOT_PATH . '/class/fckeditor/formfckeditor.php')) {
241
                require_once XOOPS_ROOT_PATH . '/class/fckeditor/formfckeditor.php';
242
                $editor = new \XoopsFormFckeditor($caption, $name, $value);
243
            }
244
            break;
245
        case 'htmlarea':
246
            if (is_readable(XOOPS_ROOT_PATH . '/class/htmlarea/formhtmlarea.php')) {
247
                require_once XOOPS_ROOT_PATH . '/class/htmlarea/formhtmlarea.php';
248
                $editor = new \XoopsFormHtmlarea($caption, $name, $value);
249
            }
250
            break;
251
        case 'dhtmltextarea':
252
        case 'dhtml':
253
            $editor = new \XoopsFormDhtmlTextArea($caption, $name, $value, 10, 50, $supplemental);
254
            break;
255
        case 'textarea':
256
            $editor = new \XoopsFormTextArea($caption, $name, $value);
257
            break;
258
        case 'tinyeditor':
259
        case 'tinymce':
260
            if (is_readable(XOOPS_ROOT_PATH . '/class/xoopseditor/tinyeditor/formtinyeditortextarea.php')) {
261
                require_once XOOPS_ROOT_PATH . '/class/xoopseditor/tinyeditor/formtinyeditortextarea.php';
262
                $editor = new \XoopsFormTinyeditorTextArea(
263
                    [
264
                        'caption' => $caption,
265
                        'name'    => $name,
266
                        'value'   => $value,
267
                        'width'   => '100%',
268
                        'height'  => '400px',
269
                    ]
270
                );
271
            }
272
            break;
273
        case 'koivi':
274
            if (is_readable(XOOPS_ROOT_PATH . '/class/wysiwyg/formwysiwygtextarea.php')) {
275
                require_once XOOPS_ROOT_PATH . '/class/wysiwyg/formwysiwygtextarea.php';
276
                $editor = new \XoopsFormWysiwygTextArea($caption, $name, $value, $width, $height, '');
277
            }
278
            break;
279
    }
280
281
    return $editor;
282
}
283
284
/**
285
 * Internal function
286
 *
287
 * @param $text
288
 * @return mixed
289
 * @copyright (c) Hervé Thouzard
290
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
291
 */
292
function DublinQuotes($text)
293
{
294
    return str_replace('"', ' ', $text);
295
}
296
297
/**
298
 * Creates all the meta datas :
299
 * - For Mozilla/Netscape and Opera the site navigation's bar
300
 * - The Dublin's Core Metadata
301
 * - The link for Firefox 2 micro summaries
302
 * - The meta keywords
303
 * - The meta description
304
 *
305
 * @param null $story
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $story is correct as it would always require null to be passed?
Loading history...
306
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
307
 * @copyright (c) Hervé Thouzard
308
 */
309
function news_CreateMetaDatas($story = null): void
310
{
311
    global $xoopsConfig, $xoTheme, $xoopsTpl;
312
    $content = '';
313
    $myts    = \MyTextSanitizer::getInstance();
314
    //    require_once XOOPS_ROOT_PATH . '/modules/news/class/class.newstopic.php';
315
316
    /**
317
     * Firefox and Opera Navigation's Bar
318
     */
319
    if (news_getmoduleoption('sitenavbar')) {
320
        $content .= sprintf("<link rel=\"Home\" title=\"%s\" href=\"%s/\">\n", $xoopsConfig['sitename'], XOOPS_URL);
321
        $content .= sprintf("<link rel=\"Contents\" href=\"%s\">\n", XOOPS_URL . '/modules/news/index.php');
322
        $content .= sprintf("<link rel=\"Search\" href=\"%s\">\n", XOOPS_URL . '/search.php');
323
        $content .= sprintf("<link rel=\"Glossary\" href=\"%s\">\n", XOOPS_URL . '/modules/news/archive.php');
324
        $content .= sprintf("<link rel=\"%s\" href=\"%s\">\n", htmlspecialchars(_NW_SUBMITNEWS, ENT_QUOTES | ENT_HTML5), XOOPS_URL . '/modules/news/submit.php');
325
        $content .= sprintf("<link rel=\"alternate\" type=\"application/rss+xml\" title=\"%s\" href=\"%s/\">\n", $xoopsConfig['sitename'], XOOPS_URL . '/backend.php');
326
327
        // Create chapters
328
        require_once XOOPS_ROOT_PATH . '/class/tree.php';
329
        //        require_once XOOPS_ROOT_PATH . '/modules/news/class/class.newstopic.php';
330
        $xt         = new NewsTopic();
331
        $allTopics  = $xt->getAllTopics(news_getmoduleoption('restrictindex'));
332
        $topic_tree = new \XoopsObjectTree($allTopics, 'topic_id', 'topic_pid');
333
        $topics_arr = $topic_tree->getAllChild(0);
334
        foreach ($topics_arr as $onetopic) {
335
            $content .= sprintf("<link rel=\"Chapter\" title=\"%s\" href=\"%s\">\n", $onetopic->topic_title(), XOOPS_URL . '/modules/news/index.php?storytopic=' . $onetopic->topic_id());
336
        }
337
    }
338
339
    /**
340
     * Meta Keywords and Description
341
     * If you have set this module's option to 'yes' and if the information was entered, then they are rendered in the page else they are computed
342
     */
343
    $meta_keywords = '';
344
    if (isset($story) && is_object($story)) {
345
        if ('' !== xoops_trim($story->keywords())) {
346
            $meta_keywords = $story->keywords();
347
        } else {
348
            $meta_keywords = news_createmeta_keywords($story->hometext() . ' ' . $story->bodytext());
349
        }
350
        if ('' !== xoops_trim($story->description())) {
351
            $meta_description = strip_tags($story->description);
352
        } else {
353
            $meta_description = strip_tags($story->title);
354
        }
355
        if (isset($xoTheme) && is_object($xoTheme)) {
356
            $xoTheme->addMeta('meta', 'keywords', $meta_keywords);
357
            $xoTheme->addMeta('meta', 'description', $meta_description);
358
        } elseif (isset($xoopsTpl) && is_object($xoopsTpl)) { // Compatibility for old Xoops versions
359
            $xoopsTpl->assign('xoops_meta_keywords', $meta_keywords);
360
            $xoopsTpl->assign('xoops_meta_description', $meta_description);
361
        }
362
    }
363
364
    /**
365
     * Dublin Core's meta datas
366
     */
367
    if (news_getmoduleoption('dublincore') && isset($story) && is_object($story)) {
368
        /** @var \XoopsConfigHandler $configHandler */
369
        $configHandler         = xoops_getHandler('config');
370
        $xoopsConfigMetaFooter = $configHandler->getConfigsByCat(XOOPS_CONF_METAFOOTER);
371
        $content               .= '<meta name="DC.Title" content="' . News\Utility::getDublinQuotes($story->title()) . "\">\n";
372
        $content               .= '<meta name="DC.Creator" content="' . News\Utility::getDublinQuotes($story->uname()) . "\">\n";
373
        $content               .= '<meta name="DC.Subject" content="' . News\Utility::getDublinQuotes($meta_keywords) . "\">\n";
374
        $content               .= '<meta name="DC.Description" content="' . News\Utility::getDublinQuotes($story->title()) . "\">\n";
375
        $content               .= '<meta name="DC.Publisher" content="' . News\Utility::getDublinQuotes($xoopsConfig['sitename']) . "\">\n";
376
        $content               .= '<meta name="DC.Date.created" scheme="W3CDTF" content="' . date('Y-m-d', $story->created) . "\">\n";
377
        $content               .= '<meta name="DC.Date.issued" scheme="W3CDTF" content="' . date('Y-m-d', $story->published) . "\">\n";
378
        $content               .= '<meta name="DC.Identifier" content="' . XOOPS_URL . '/modules/news/article.php?storyid=' . $story->storyid() . "\">\n";
379
        $content               .= '<meta name="DC.Source" content="' . XOOPS_URL . "\">\n";
380
        $content               .= '<meta name="DC.Language" content="' . _LANGCODE . "\">\n";
381
        $content               .= '<meta name="DC.Relation.isReferencedBy" content="' . XOOPS_URL . '/modules/news/index.php?storytopic=' . $story->topicid() . "\">\n";
382
        if (isset($xoopsConfigMetaFooter['meta_copyright'])) {
383
            $content .= '<meta name="DC.Rights" content="' . News\Utility::getDublinQuotes($xoopsConfigMetaFooter['meta_copyright']) . "\">\n";
384
        }
385
    }
386
387
    /**
388
     * Firefox 2 micro summaries
389
     */
390
    if (news_getmoduleoption('firefox_microsummaries')) {
391
        $content .= sprintf("<link rel=\"microsummary\" href=\"%s\">\n", XOOPS_URL . '/modules/news/micro_summary.php');
392
    }
393
394
    if (isset($xoopsTpl) && is_object($xoopsTpl)) {
395
        $xoopsTpl->assign('xoops_module_header', $content);
396
    }
397
}
398
399
/**
400
 * Create the meta keywords based on the content
401
 *
402
 * @param $content
403
 * @return string
404
 * @copyright (c) Hervé Thouzard
405
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
406
 */
407
function news_createmeta_keywords($content)
408
{
409
    require_once XOOPS_ROOT_PATH . '/modules/news/config.php';
410
    // require_once XOOPS_ROOT_PATH . '/modules/news/class/blacklist.php';
411
    // require_once XOOPS_ROOT_PATH . '/modules/news/class/registryfile.php';
412
413
    if (!$cfg['meta_keywords_auto_generate']) {
414
        return '';
415
    }
416
    $registry = new Registryfile('news_metagen_options.txt');
417
    //    $tcontent = '';
418
    $tcontent = $registry->getfile();
419
    if ('' !== xoops_trim($tcontent)) {
420
        [$keywordscount, $keywordsorder] = explode(',', $tcontent);
421
    } else {
422
        $keywordscount = $cfg['meta_keywords_count'];
423
        $keywordsorder = $cfg['meta_keywords_order'];
424
    }
425
426
    $tmp = [];
427
    // Search for the "Minimum keyword length"
428
    if (Request::hasVar('news_keywords_limit', 'SESSION')) {
429
        $limit = $_SESSION['news_keywords_limit'];
430
    } else {
431
        /** @var \XoopsConfigHandler $configHandler */
432
        $configHandler                   = xoops_getHandler('config');
433
        $xoopsConfigSearch               = $configHandler->getConfigsByCat(XOOPS_CONF_SEARCH);
434
        $limit                           = $xoopsConfigSearch['keyword_min'];
435
        $_SESSION['news_keywords_limit'] = $limit;
436
    }
437
    $myts            = \MyTextSanitizer::getInstance();
438
    $content         = str_replace('<br>', ' ', $content);
439
    $content         = $myts->undoHtmlSpecialChars($content);
440
    $content         = strip_tags($content);
441
    $content         = \mb_strtolower($content);
442
    $search_pattern  = [
443
        '&nbsp;',
444
        "\t",
445
        "\r\n",
446
        "\r",
447
        "\n",
448
        ',',
449
        '.',
450
        "'",
451
        ';',
452
        ':',
453
        ')',
454
        '(',
455
        '"',
456
        '?',
457
        '!',
458
        '{',
459
        '}',
460
        '[',
461
        ']',
462
        '<',
463
        '>',
464
        '/',
465
        '+',
466
        '-',
467
        '_',
468
        '\\',
469
        '*',
470
    ];
471
    $replace_pattern = [
472
        ' ',
473
        ' ',
474
        ' ',
475
        ' ',
476
        ' ',
477
        ' ',
478
        ' ',
479
        ' ',
480
        '',
481
        '',
482
        '',
483
        '',
484
        '',
485
        '',
486
        '',
487
        '',
488
        '',
489
        '',
490
        '',
491
        '',
492
        '',
493
        '',
494
        '',
495
        '',
496
        '',
497
        '',
498
        '',
499
    ];
500
    $content         = str_replace($search_pattern, $replace_pattern, $content);
501
    $keywords        = explode(' ', $content);
502
    switch ($keywordsorder) {
503
        case 0: // Ordre d'apparition dans le texte
504
            $keywords = array_unique($keywords);
505
            break;
506
        case 1: // Ordre de fréquence des mots
507
            $keywords = array_count_values($keywords);
508
            asort($keywords);
509
            $keywords = array_keys($keywords);
510
            break;
511
        case 2: // Ordre inverse de la fréquence des mots
512
            $keywords = array_count_values($keywords);
513
            arsort($keywords);
514
            $keywords = array_keys($keywords);
515
            break;
516
    }
517
    // Remove black listed words
518
    $metablack = new Blacklist();
519
    $words     = $metablack->getAllKeywords();
520
    $keywords  = $metablack->remove_blacklisted($keywords);
521
522
    foreach ($keywords as $keyword) {
523
        if (mb_strlen($keyword) >= $limit && !is_numeric($keyword)) {
524
            $tmp[] = $keyword;
525
        }
526
    }
527
    $tmp = array_slice($tmp, 0, $keywordscount);
528
    if (count($tmp) > 0) {
529
        return implode(',', $tmp);
530
    }
531
    if (!isset($configHandler) || !is_object($configHandler)) {
532
        /** @var \XoopsConfigHandler $configHandler */
533
        $configHandler = xoops_getHandler('config');
534
    }
535
    $xoopsConfigMetaFooter = $configHandler->getConfigsByCat(XOOPS_CONF_METAFOOTER);
536
    return $xoopsConfigMetaFooter['meta_keywords'] ?? '';
537
}
538
539
/**
540
 * Remove module's cache
541
 *
542
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
543
 * @copyright (c) Hervé Thouzard
544
 */
545
function news_updateCache(): void
546
{
547
    global $xoopsModule;
548
    $folder  = $xoopsModule->getVar('dirname');
549
    $tpllist = [];
550
    require_once XOOPS_ROOT_PATH . '/class/xoopsblock.php';
551
    require_once XOOPS_ROOT_PATH . '/class/template.php';
552
    /** @var \XoopsTplfileHandler $tplfileHandler */
553
    $tplfileHandler = xoops_getHandler('tplfile');
554
    $tpllist        = $tplfileHandler->find(null, null, null, $folder);
555
    $xoopsTpl       = new \XoopsTpl();
556
    xoops_template_clear_module_cache($xoopsModule->getVar('mid')); // Clear module's blocks cache
557
558
    // Remove cache for each page.
559
    foreach ($tpllist as $onetemplate) {
560
        if ('module' === $onetemplate->getVar('tpl_type')) {
561
            // Note, I've been testing all the other methods (like the one of Smarty) and none of them run, that's why I have used this code
562
            $files_del = [];
563
            $files_del = glob(XOOPS_CACHE_PATH . '/*' . $onetemplate->getVar('tpl_file') . '*', GLOB_NOSORT);
564
            if (count($files_del) > 0) {
565
                foreach ($files_del as $one_file) {
566
                    unlink($one_file);
567
                }
568
            }
569
        }
570
    }
571
}
572
573
/**
574
 * Verify that a mysql table exists
575
 *
576
 * @param $tablename
577
 * @return bool
578
 * @copyright (c) Hervé Thouzard
579
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
580
 */
581
function news_TableExists($tablename)
582
{
583
    global $xoopsDB;
584
    $result = $xoopsDB->queryF("SHOW TABLES LIKE '$tablename'");
585
586
    return ($xoopsDB->getRowsNum($result) > 0);
587
}
588
589
/**
590
 * Verify that a field exists inside a mysql table
591
 *
592
 * @param $fieldname
593
 * @param $table
594
 * @return bool
595
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
596
 * @copyright (c) Hervé Thouzard
597
 */
598
function news_FieldExists($fieldname, $table)
599
{
600
    global $xoopsDB;
601
    $result = $xoopsDB->queryF("SHOW COLUMNS FROM   $table LIKE '$fieldname'");
602
603
    return ($xoopsDB->getRowsNum($result) > 0);
604
}
605
606
/**
607
 * Add a field to a mysql table
608
 *
609
 * @param $field
610
 * @param $table
611
 * @return bool|\mysqli_result
612
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
613
 * @copyright (c) Hervé Thouzard
614
 */
615
function news_AddField($field, $table)
616
{
617
    global $xoopsDB;
618
    $result = $xoopsDB->queryF('ALTER TABLE ' . $table . " ADD $field;");
619
620
    return $result;
621
}
622
623
/**
624
 * Verify that the current user is a member of the Admin group
625
 */
626
function news_is_admin_group()
627
{
628
    global $xoopsUser, $xoopsModule;
629
    if (is_object($xoopsUser)) {
630
        if (in_array('1', $xoopsUser->getGroups(), true)) {
631
            return true;
632
        }
633
        if ($xoopsUser->isAdmin($xoopsModule->mid())) {
634
            return true;
635
        }
636
637
        return false;
638
    }
639
640
    return false;
641
}
642
643
/**
644
 * Verify if the current "user" is a bot or not
645
 *
646
 * If you have a problem with this function, insert the folowing code just before the line if (\Xmf\Request::hasVar('news_cache_bot', 'SESSION'))) { :
647
 * return false;
648
 *
649
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
650
 * @copyright (c) Hervé Thouzard
651
 */
652
function news_isbot()
653
{
654
    if (Request::hasVar('news_cache_bot', 'SESSION')) {
655
        return $_SESSION['news_cache_bot'];
656
    }
657
    // Add here every bot you know separated by a pipe | (not matter with the upper or lower cases)
658
    // If you want to see the result for yourself, add your navigator's user agent at the end (mozilla for example)
659
    $botlist      = 'AbachoBOT|Arachnoidea|ASPSeek|Atomz|cosmos|crawl25-public.alexa.com|CrawlerBoy Pinpoint.com|Crawler|DeepIndex|EchO!|exabot|Excalibur Internet Spider|FAST-WebCrawler|Fluffy the spider|GAIS Robot/1.0B2|GaisLab data gatherer|Google|Googlebot-Image|googlebot|Gulliver|ia_archiver|Infoseek|Links2Go|Lycos_Spider_(modspider)|Lycos_Spider_(T-Rex)|MantraAgent|Mata Hari|Mercator|MicrosoftPrototypeCrawler|[email protected]|MSNBOT|NEC Research Agent|NetMechanic|Nokia-WAPToolkit|nttdirectory_robot|Openfind|Oracle Ultra Search|PicoSearch|Pompos|Scooter|Slider_Search_v1-de|Slurp|Slurp.so|SlySearch|Spider|Spinne|SurferF3|Surfnomore Spider|suzuran|teomaagent1|TurnitinBot|Ultraseek|VoilaBot|vspider|W3C_Validator|Web Link Validator|WebTrends|WebZIP|whatUseek_winona|WISEbot|Xenu Link Sleuth|ZyBorg';
660
    $botlist      = \mb_strtoupper($botlist);
661
    $currentagent = \mb_strtoupper(xoops_getenv('HTTP_USER_AGENT'));
662
    $retval       = false;
663
    $botarray     = explode('|', $botlist);
664
    foreach ($botarray as $onebot) {
665
        if (false !== mb_strpos($currentagent, $onebot)) {
666
            $retval = true;
667
            break;
668
        }
669
    }
670
671
    $_SESSION['news_cache_bot'] = $retval;
672
673
    return $retval;
674
}
675
676
/**
677
 * Create an infotip
678
 *
679
 * @param $text
680
 * @return string|null
681
 * @copyright (c) Hervé Thouzard
682
 * @author        Hervé Thouzard (https://www.herve-thouzard.com)
683
 */
684
function news_make_infotips($text)
685
{
686
    $infotips = news_getmoduleoption('infotips');
687
    if ($infotips > 0) {
688
        $myts = \MyTextSanitizer::getInstance();
689
690
        return htmlspecialchars(xoops_substr(strip_tags($text), 0, $infotips), ENT_QUOTES | ENT_HTML5);
691
    }
692
693
    return null;
694
}
695
696
/**
697
 * @param string $string
698
 * @return string
699
 * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
700
 *           <amos dot robinson at gmail dot com>
701
 */
702
function news_close_tags($string)
703
{
704
    // match opened tags
705
    if (preg_match_all('/<([a-z\:\-]+)[^\/]>/', $string, $start_tags)) {
706
        $start_tags = $start_tags[1];
707
        // match closed tags
708
        if (preg_match_all('/<\/([a-z]+)>/', $string, $end_tags)) {
709
            $complete_tags = [];
710
            $end_tags      = $end_tags[1];
711
712
            foreach ($start_tags as $key => $val) {
713
                $posb = array_search($val, $end_tags, true);
714
                if (is_int($posb)) {
715
                    unset($end_tags[$posb]);
716
                } else {
717
                    $complete_tags[] = $val;
718
                }
719
            }
720
        } else {
721
            $complete_tags = $start_tags;
722
        }
723
724
        $complete_tags = array_reverse($complete_tags);
725
        foreach ($complete_tags as $iValue) {
726
            $string .= '</' . $iValue . '>';
727
        }
728
    }
729
730
    return $string;
731
}
732
733
/**
734
 * Smarty truncate_tagsafe modifier plugin
735
 *
736
 * Type:     modifier<br>
737
 * Name:     truncate_tagsafe<br>
738
 * Purpose:  Truncate a string to a certain length if necessary,
739
 *           optionally splitting in the middle of a word, and
740
 *           appending the $etc string or inserting $etc into the middle.
741
 *           Makes sure no tags are left half-open or half-closed
742
 *           (e.g. "Banana in a <a...")
743
 *
744
 * @param mixed $string
745
 * @param mixed $length
746
 * @param mixed $etc
747
 * @param mixed $break_words
748
 *
749
 * @return string
750
 * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
751
 *           <amos dot robinson at gmail dot com>
752
 */
753
function news_truncate_tagsafe($string, $length = 80, $etc = '...', $break_words = false)
754
{
755
    if (0 == $length) {
756
        return '';
757
    }
758
    if (mb_strlen($string) > $length) {
759
        $length -= mb_strlen($etc);
760
        if (!$break_words) {
761
            $string = preg_replace('/\s+?(\S+)?$/', '', mb_substr($string, 0, $length + 1));
762
            $string = preg_replace('/<[^>]*$/', '', $string);
763
            $string = news_close_tags($string);
764
        }
765
766
        return $string . $etc;
767
    }
768
769
    return $string;
770
}
771
772
/**
773
 * Resize a Picture to some given dimensions (using the wideImage library)
774
 *
775
 * @param string $src_path      Picture's source
776
 * @param string $dst_path      Picture's destination
777
 * @param int    $param_width   Maximum picture's width
778
 * @param int    $param_height  Maximum picture's height
779
 * @param bool   $keep_original Do we have to keep the original picture ?
780
 * @param string $fit           Resize mode (see the wideImage library for more information)
781
 *
782
 * @return bool
783
 */
784
function news_resizePicture(
785
    $src_path,
786
    $dst_path,
787
    $param_width,
788
    $param_height,
789
    $keep_original = false,
790
    $fit = 'inside'
791
) {
792
    //    require_once XOOPS_PATH . '/vendor/wideimage/WideImage.php';
793
    $resize            = true;
794
    $pictureDimensions = getimagesize($src_path);
795
    if (is_array($pictureDimensions)) {
796
        $pictureWidth  = $pictureDimensions[0];
797
        $pictureHeight = $pictureDimensions[1];
798
        if ($pictureWidth < $param_width && $pictureHeight < $param_height) {
799
            $resize = false;
800
        }
801
    }
802
803
    $img = WideImage::load($src_path);
804
    if ($resize) {
805
        $result = $img->resize($param_width, $param_height, $fit);
806
        $result->saveToFile($dst_path);
807
    } else {
808
        @copy($src_path, $dst_path);
809
    }
810
    if (!$keep_original) {
811
        @unlink($src_path);
812
    }
813
814
    return true;
815
}
816