Issues (330)

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/Utility.php (1 issue)

1
<?php
2
3
namespace XoopsModules\Lexikon;
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    XOOPS Project (https://xoops.org)
17
 * @license      GNU GPL 2 or later (https://www.gnu.org/licenses/gpl-2.0.html)
18
 * @author      XOOPS Development Team, hsalazar
19
 */
20
21
use Xmf\Module\Admin;
22
use Xmf\Request;
23
24
/** @var Helper $helper */
25
use XoopsModules\Lexikon\Common;
26
27
/**
28
 * Class Utility
29
 */
30
class Utility extends Common\SysUtility
31
{
32
    //--------------- Custom module methods -----------------------------
33
    /**
34
     * static::getLinkedUnameFromId()
35
     *
36
     * @param int $userid Userid of author etc
37
     * @param int $name   :  0 Use Usenamer 1 Use realname
38
     * @return string
39
     */
40
    public static function getLinkedUnameFromId($userid = 0, $name = 0)
41
    {
42
        if (!\is_numeric($userid)) {
43
            return $userid;
44
        }
45
46
        $userid = (int)$userid;
47
        if ($userid > 0) {
48
            /** @var \XoopsMemberHandler $memberHandler */
49
            $memberHandler = \xoops_getHandler('member');
50
            $user          = $memberHandler->getUser($userid);
51
52
            if (\is_object($user)) {
53
                $ts        = \MyTextSanitizer::getInstance();
54
                $username  = $user->getVar('uname');
55
                $usernameu = $user->getVar('name');
56
57
                if ($name && !empty($usernameu)) {
58
                    $username = $user->getVar('name');
59
                }
60
                if (!empty($usernameu)) {
61
                    $linkeduser = "$usernameu [<a href='" . XOOPS_URL . '/userinfo.php?uid=' . $userid . "'>" . $ts->htmlSpecialChars($username) . '</a>]';
62
                } else {
63
                    $linkeduser = "<a href='" . XOOPS_URL . '/userinfo.php?uid=' . $userid . "'>" . \ucfirst($ts->htmlSpecialChars($username)) . '</a>';
64
                }
65
66
                return $linkeduser;
67
            }
68
        }
69
70
        return $GLOBALS['xoopsConfig']['anonymous'];
71
    }
72
73
    /**
74
     * @param $user
75
     */
76
    public static function getUserForm($user)
77
    {
78
        global $xoopsDB, $xoopsConfig;
79
80
        echo "<select name='author'>";
81
        echo "<option value='-1'>------</option>";
82
        $result = $xoopsDB->query('SELECT uid, uname FROM ' . $xoopsDB->prefix('users') . ' ORDER BY uname');
83
84
        while (list($uid, $uname) = $xoopsDB->fetchRow($result)) {
85
            if ($uid == $user) {
86
                $opt_selected = 'selected';
87
            } else {
88
                $opt_selected = '';
89
            }
90
            echo "<option value='" . $uid . "' $opt_selected>" . $uname . '</option>';
91
        }
92
        echo '</select></div>';
93
    }
94
95
    /**
96
     *
97
     */
98
    public static function calculateTotals()
99
    {
100
        global $xoopsUser, $xoopsDB, $xoopsModule;
101
        $groups           = \is_object($xoopsUser) ? $xoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;
102
        $grouppermHandler = \xoops_getHandler('groupperm');
103
104
        $result01 = $xoopsDB->query('SELECT categoryID, total FROM ' . $xoopsDB->prefix('lxcategories') . ' ');
105
        [$totalcategories] = $xoopsDB->getRowsNum($result01);
106
        while (list($categoryID, $total) = $xoopsDB->fetchRow($result01)) {
107
            if ($grouppermHandler->checkRight('lexikon_view', $categoryID, $groups, $xoopsModule->getVar('mid'))) {
108
                $newcount = self::countByCategory($categoryID);
109
                $xoopsDB->queryF('UPDATE ' . $xoopsDB->prefix('lxcategories') . " SET total = '$newcount' WHERE categoryID = '$categoryID'");
110
            }
111
        }
112
    }
113
114
    /**
115
     * @param $c
116
     * @return int
117
     */
118
    public static function countByCategory($c)
119
    {
120
        global $xoopsUser, $xoopsDB, $xoopsModule;
121
        $groups           = \is_object($xoopsUser) ? $xoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;
122
        $grouppermHandler = \xoops_getHandler('groupperm');
123
        $count            = 0;
124
        $sql              = $xoopsDB->query('SELECT entryID FROM ' . $xoopsDB->prefix('lxentries') . " WHERE offline = '0' AND categoryID = '$c'");
125
        while (false !== ($myrow = $xoopsDB->fetchArray($sql))) {
126
            ++$count;
127
        }
128
129
        return $count;
130
    }
131
132
    /**
133
     * @return int
134
     */
135
    public static function countCats()
136
    {
137
        global $xoopsUser, $xoopsModule;
138
        $grouppermHandler = \xoops_getHandler('groupperm');
139
        $groups           = \is_object($xoopsUser) ? $xoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;
140
        $totalcats        = $grouppermHandler->getItemIds('lexikon_view', $groups, $xoopsModule->getVar('mid'));
141
142
        return \count($totalcats);
143
    }
144
145
    /**
146
     * @return mixed
147
     */
148
    public static function countWords()
149
    {
150
        global $xoopsUser, $xoopsDB;
151
        $grouppermHandler = \xoops_getHandler('groupperm');
152
        $groups           = \is_object($xoopsUser) ? $xoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;
153
        /** @var \XoopsModuleHandler $moduleHandler */
154
        $moduleHandler = \xoops_getHandler('module');
155
        $module        = $moduleHandler->getByDirname('lexikon');
156
        $module_id     = $module->getVar('mid');
157
        $allowed_cats  = $grouppermHandler->getItemIds('lexikon_view', $groups, $module_id);
158
        $catids        = \implode(',', $allowed_cats);
159
        $catperms      = " AND categoryID IN ($catids) ";
160
161
        $pubwords       = $xoopsDB->query('SELECT * FROM ' . $xoopsDB->prefix('lxentries') . " WHERE submit = '0' AND offline ='0' AND request = '0' " . $catperms . ' ');
162
        $publishedwords = $xoopsDB->getRowsNum($pubwords);
163
164
        return $publishedwords;
165
    }
166
167
    // To display the list of categories
168
169
    /**
170
     * @return array
171
     */
172
    public static function getCategoryArray()
173
    {
174
        global $xoopsDB, $xoopsUser, $xoopsModule;
175
176
        $helper           = Helper::getInstance();
177
        $myts             = \MyTextSanitizer::getInstance();
178
        $groups           = \is_object($xoopsUser) ? $xoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;
179
        $grouppermHandler = \xoops_getHandler('groupperm');
180
        $block0           = [];
181
        $count            = 1;
182
        $resultcat        = $xoopsDB->query('SELECT categoryID, name, total, logourl FROM ' . $xoopsDB->prefix('lxcategories') . ' ORDER BY weight ASC');
183
        while (list($catID, $name, $total, $logourl) = $xoopsDB->fetchRow($resultcat)) {
184
            if ($grouppermHandler->checkRight('lexikon_view', $catID, $groups, $xoopsModule->getVar('mid'))) {
185
                $catlinks = [];
186
                ++$count;
187
                if ($logourl && 'http://' !== $logourl) {
188
                    $logourl = \htmlspecialchars($logourl, \ENT_QUOTES | \ENT_HTML5);
189
                } else {
190
                    $logourl = '';
191
                }
192
                $xoopsModule          = \XoopsModule::getByDirname('lexikon');
193
                $catlinks['id']       = (int)$catID;
194
                $catlinks['total']    = (int)$total;
195
                $catlinks['linktext'] = \htmlspecialchars($name, \ENT_QUOTES | \ENT_HTML5);
196
                $catlinks['image']    = $logourl;
197
                $catlinks['count']    = $count;
198
199
                $block0['categories'][] = $catlinks;
200
            }
201
        }
202
203
        return $block0;
204
    }
205
206
    /**
207
     * @return array
208
     */
209
    public static function getAlphaArray()
210
    {
211
        global $xoopsUser, $xoopsDB, $xoopsModule;
212
        $grouppermHandler = \xoops_getHandler('groupperm');
213
        $groups           = \is_object($xoopsUser) ? $xoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;
214
        /** @var \XoopsModuleHandler $moduleHandler */
215
        $moduleHandler = \xoops_getHandler('module');
216
        $module        = $moduleHandler->getByDirname('lexikon');
217
        $module_id     = $module->getVar('mid');
218
        $allowed_cats  = $grouppermHandler->getItemIds('lexikon_view', $groups, $module_id);
219
        $catids        = \implode(',', $allowed_cats);
220
        $catperms      = " AND categoryID IN ($catids) ";
221
        $alpha         = [];
222
        /**
223
         * @param $a
224
         * @return null|string|string[]
225
         */
226
        function unichr($a)
227
        {
228
            return mb_convert_encoding(\pack('N', $a), mb_internal_encoding(), 'UCS-4BE');
229
        }
230
231
        for ($a = 48; $a < (48 + 10); ++$a) {
232
            $letterlinks             = [];
233
            $initial                 = unichr($a);
234
            $sql                     = $xoopsDB->query('SELECT entryID FROM ' . $xoopsDB->prefix('lxentries') . " WHERE init = '$initial' AND submit = '0' AND offline ='0' AND request = '0' " . $catperms . '');
235
            $howmany                 = $xoopsDB->getRowsNum($sql);
236
            $letterlinks['total']    = $howmany;
237
            $letterlinks['id']       = unichr($a);
238
            $letterlinks['linktext'] = unichr($a);
239
240
            $alpha['initial'][] = $letterlinks;
241
        }
242
        for ($a = 65; $a < (65 + 26); ++$a) {
243
            $letterlinks             = [];
244
            $initial                 = unichr($a);
245
            $sql                     = $xoopsDB->query('SELECT entryID FROM ' . $xoopsDB->prefix('lxentries') . " WHERE init = '$initial' AND submit = '0' AND offline ='0' AND request = '0' " . $catperms . '');
246
            $howmany                 = $xoopsDB->getRowsNum($sql);
247
            $letterlinks['total']    = $howmany;
248
            $letterlinks['id']       = unichr($a);
249
            $letterlinks['linktext'] = unichr($a);
250
251
            $alpha['initial'][] = $letterlinks;
252
        }
253
        /*for ($a = 1040; $a < (1040 + 32); ++$a) {
254
            $letterlinks             = [];
255
            $initial                 = unichr($a);
256
            $sql                     = $xoopsDB->query('SELECT entryID FROM '
257
                                                           . $xoopsDB->prefix('lxentries')
258
                                                           . " WHERE init = '$initial' AND submit = '0' AND offline ='0' AND request = '0' "
259
                                                           . $catperms
260
                                                           . '');
261
            $howmany                 = $xoopsDB->getRowsNum($sql);
262
            $letterlinks['total']    = $howmany;
263
            $letterlinks['id']       = unichr($a);
264
            $letterlinks['linktext'] = unichr($a);
265
            $alpha['initial'][] = $letterlinks;
266
        }*/
267
268
        return $alpha;
269
    }
270
271
    /**
272
     * chr() with unicode support
273
     * I found this on this site http://en.php.net/chr
274
     * don't take credit for this.
275
     * @param $initials
276
     * @return string
277
     */
278
    public static function getUchr($initials)
279
    {
280
        if (\is_scalar($initials)) {
281
            $initials = \func_get_args();
282
        }
283
        $str = '';
284
        foreach ($initials as $init) {
285
            $str .= \html_entity_decode('&#' . $init . ';', \ENT_NOQUOTES, 'UTF-8');
286
        }
287
288
        return $str;
289
    }
290
291
    /* sample */
292
    /*
293
        echo static::getUchr(23383); echo '<br>';
294
        echo static::getUchr(23383,215,23383); echo '<br>';
295
        echo static::getUchr(array(23383,215,23383,215,23383)); echo '<br>';
296
    */
297
298
    // Functional links
299
300
    /**
301
     * @param $variable
302
     * @return string
303
     */
304
    public static function getServiceLinks($variable)
305
    {
306
        global $xoopsUser, $xoopsDB, $xoopsModule, $xoopsConfig, $entrytype;
307
308
        $helper = Helper::getInstance();
309
310
        /** @var \XoopsModuleHandler $moduleHandler */
311
        $moduleHandler = \xoops_getHandler('module');
312
        $moduleInfo    = $moduleHandler->get($xoopsModule->getVar('mid'));
313
        $pathIcon16    = Admin::iconUrl('', 16);
314
315
        $srvlinks = '';
316
        if ($xoopsUser) {
317
            if ($xoopsUser->isAdmin()) {
318
                $srvlinks .= '<a TITLE="'
319
                             . _EDIT
320
                             . '" href="admin/entry.php?op=mod&entryID='
321
                             . $variable['id']
322
                             . '" target="_blank"><img src="'
323
                             . $pathIcon16
324
                             . '/edit.png"   alt="'
325
                             . _MD_LEXIKON_EDITTERM
326
                             . '" style="width:16px; height:16px;"></a>&nbsp;<a TITLE="'
327
                             . _DELETE
328
                             . '" href="admin/entry.php?op=del&entryID='
329
                             . $variable['id']
330
                             . '" target="_self"><img src="'
331
                             . $pathIcon16
332
                             . '/delete.png" alt="'
333
                             . _MD_LEXIKON_DELTERM
334
                             . '" style="width:16px; height:16px;"></a>&nbsp;';
335
            }
336
        }
337
        if ('1' != $entrytype) {
338
            $srvlinks .= '<a TITLE="'
339
                         . _MD_LEXIKON_PRINTTERM
340
                         . '" href="print.php?entryID='
341
                         . $variable['id']
342
                         . '" target="_blank"><img src="'
343
                         . $pathIcon16
344
                         . '/printer.png"  alt="'
345
                         . _MD_LEXIKON_PRINTTERM
346
                         . '" style="width:16px; height:16px;"></a>&nbsp;<a TITLE="'
347
                         . _MD_LEXIKON_SENDTOFRIEND
348
                         . '" href="mailto:?subject='
349
                         . \sprintf(_MD_LEXIKON_INTENTRY, $xoopsConfig['sitename'])
350
                         . '&amp;body='
351
                         . \sprintf(_MD_LEXIKON_INTENTRYFOUND, $xoopsConfig['sitename'])
352
                         . ': '
353
                         . XOOPS_URL
354
                         . '/modules/'
355
                         . $xoopsModule->dirname()
356
                         . '/entry.php?entryID='
357
                         . $variable['id']
358
                         . ' " target="_blank"><img src="'
359
                         . $pathIcon16
360
                         . '/mail_replay.png" alt="'
361
                         . _MD_LEXIKON_SENDTOFRIEND
362
                         . '" style="width:16px; height:16px;"></a>&nbsp;';
363
            if ((0 != $helper->getConfig('com_rule'))
364
                && (!empty($helper->getConfig('com_anonpost'))
365
                    || \is_object($xoopsUser))) {
366
                $srvlinks .= '<a TITLE="' . _COMMENTS . '?" href="comment_new.php?com_itemid=' . $variable['id'] . '" target="_parent"><img src="assets/images/comments.gif" alt="' . _COMMENTS . '?" style="width:16px; height:16px;"></a>&nbsp;';
367
            }
368
        }
369
370
        return $srvlinks;
371
    }
372
373
    // entry footer
374
375
    /**
376
     * @param $variable
377
     * @return string
378
     */
379
    public static function getServiceLinksNew($variable)
380
    {
381
        global $xoopsUser, $xoopsDB, $xoopsModule, $xoopsConfig, $myts;
382
383
        $helper    = Helper::getInstance();
384
        $srvlinks2 = '<a TITLE="'
385
                     . _MD_LEXIKON_PRINTTERM
386
                     . '" href="print.php?entryID='
387
                     . $variable['id']
388
                     . '" target="_blank"><img src="assets/images/print.gif" alt="'
389
                     . _MD_LEXIKON_PRINTTERM
390
                     . '" style="vertical-align: middle; width:16px; height:16px; margin: 2px 4px;"> '
391
                     . _MD_LEXIKON_PRINTTERM2
392
                     . '</a>&nbsp; <a TITLE="'
393
                     . _MD_LEXIKON_SENDTOFRIEND
394
                     . '" href="mailto:?subject='
395
                     . \sprintf(_MD_LEXIKON_INTENTRY, $xoopsConfig['sitename'])
396
                     . '&amp;body='
397
                     . \sprintf(_MD_LEXIKON_INTENTRYFOUND, $xoopsConfig['sitename'])
398
                     . ': '
399
                     . $variable['term']
400
                     . ' '
401
                     . XOOPS_URL
402
                     . '/modules/'
403
                     . $xoopsModule->dirname()
404
                     . '/entry.php?entryID='
405
                     . $variable['id']
406
                     . ' " target="_blank"><img src="assets/images/friend.gif" alt="'
407
                     . _MD_LEXIKON_SENDTOFRIEND
408
                     . '" style="vertical-align: middle; width:16px; height:16px; margin: 2px 4px;"> '
409
                     . _MD_LEXIKON_SENDTOFRIEND2
410
                     . '</a>&nbsp;';
411
412
        return $srvlinks2;
413
    }
414
415
    /**
416
     * @return \XoopsThemeForm
417
     */
418
    public static function getFormSearch($type = '3', $categoryID = '0', $term = '')
419
    {
420
        global $xoopsUser, $xoopsDB, $xoopsModule, $xoopsConfig;
421
422
        $helper = Helper::getInstance();
423
424
        $grouppermHandler = \xoops_getHandler('groupperm');
425
        $groups           = \is_object($xoopsUser) ? $xoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;
426
        $action = $_SERVER['REQUEST_URI'];
0 ignored issues
show
The assignment to $action is dead and can be removed.
Loading history...
427
428
        // Get Theme Form
429
        \xoops_load('XoopsFormLoader');
430
        $form = new \XoopsThemeForm(_MD_LEXIKON_LOOKON, 'form', 'search.php', 'post', true);
431
        $form->setExtra('enctype="multipart/form-data"');
432
        // Form select search type
433
        $searchTypeSelect = new \XoopsFormSelect(\_MD_LEXIKON_LOOKON, 'type', $type);
434
        $searchTypeSelect->addOption('1', _MD_LEXIKON_TERMS);
435
        $searchTypeSelect->addOption('2', _MD_LEXIKON_DEFINS);
436
        $searchTypeSelect->addOption('3', _MD_LEXIKON_TERMSDEFS);
437
        $form->addElement($searchTypeSelect);
438
        // form select cats
439
        if (1 == $helper->getConfig('multicats')) {
440
            $resultcat  = $xoopsDB->query('SELECT categoryID, name FROM ' . $xoopsDB->prefix('lxcategories') . ' ORDER BY categoryID');
441
            $searchCatSelect = new \XoopsFormSelect(\_MD_LEXIKON_LOOKON, 'categoryID', $categoryID);
442
            $searchCatSelect->addOption(0, _MD_LEXIKON_ALLOFTHEM);
443
            while (list($categoryID, $name) = $xoopsDB->fetchRow($resultcat)) {
444
                if ($grouppermHandler->checkRight('lexikon_view', (int)$categoryID, $groups, $xoopsModule->getVar('mid'))) {
445
                    $searchCatSelect->addOption($categoryID, $categoryID . ' : ' . $name);
446
                }
447
            }
448
            $form->addElement($searchCatSelect);
449
        }
450
        // Form Text term
451
        $form->addElement(new \XoopsFormText(\_MD_LEXIKON_TERM, 'term', 30, 255, $term), true);
452
         // To Save
453
        $form->addElement(new \XoopsFormHidden('op', 'save'));
454
        $form->addElement(new \XoopsFormButton('', 'submit', \_MD_LEXIKON_SEARCH, 'submit'));
455
456
        return $form;
457
    }
458
    
459
    /**
460
     * @param $needle
461
     * @param $haystack
462
     * @param $hlS
463
     * @param $hlE
464
     * @return string
465
     */
466
    public static function getHTMLHighlight($needle, $haystack, $hlS, $hlE)
467
    {
468
        $parts = \explode('>', $haystack);
469
        foreach ($parts as $key => $part) {
470
            $pL = '';
471
            $pR = '';
472
473
            if (false === ($pos = mb_strpos($part, '<'))) {
474
                $pL = $part;
475
            } elseif ($pos > 0) {
476
                $pL = mb_substr($part, 0, $pos);
477
                $pR = mb_substr($part, $pos, mb_strlen($part));
478
            }
479
            if ('' != $pL) {
480
                $parts[$key] = \preg_replace('|(' . \quotemeta($needle) . ')|iU', $hlS . '\\1' . $hlE, $pL) . $pR;
481
            }
482
        }
483
484
        return \implode('>', $parts);
485
    }
486
487
    /* *******************************************************************************
488
     * Most of the following functions are modified functions from Herve's News Module
489
     * other functions are from  AMS by Novasmart/Mithrandir
490
     * others from Red Mexico Soft Rmdp
491
     * others from Xhelp 0.78 thanks to ackbarr and eric_juden
492
     * *******************************************************************************
493
     */
494
495
    // Create the meta keywords based on content
496
497
    /**
498
     * @param $content
499
     */
500
    public static function extractKeywords($content)
501
    {
502
        global $xoopsTpl, $xoTheme, $xoopsModule;
503
504
        $helper = Helper::getInstance();
505
        require_once XOOPS_ROOT_PATH . '/modules/lexikon/include/common.inc.php';
506
        $keywords_count = $helper->getConfig('metakeywordsnum');
507
        $tmp            = [];
508
        if (\Xmf\Request::hasVar('xoops_keywords_limit', 'SESSION')) {    // Search the "Minimum keyword length"
509
            $limit = $_SESSION['xoops_keywords_limit'];
510
        } else {
511
            /** @var \XoopsConfigHandler $configHandler */
512
            $configHandler                    = \xoops_getHandler('config');
513
            $xoopsConfigSearch                = $configHandler->getConfigsByCat(\XOOPS_CONF_SEARCH);
514
            $limit                            = $xoopsConfigSearch['keyword_min'];
515
            $_SESSION['xoops_keywords_limit'] = $limit;
516
        }
517
        $myts            = \MyTextSanitizer::getInstance();
518
        $content         = \str_replace('<br>', ' ', $content);
519
        $content         = $myts->undoHtmlSpecialChars($content);
520
        $content         = \strip_tags($content);
521
        $content         = mb_strtolower($content);
522
        $search_pattern  = [
523
            '&nbsp;',
524
            "\t",
525
            "\r\n",
526
            "\r",
527
            "\n",
528
            ',',
529
            '.',
530
            "'",
531
            ';',
532
            ':',
533
            ')',
534
            '(',
535
            '"',
536
            '?',
537
            '!',
538
            '{',
539
            '}',
540
            '[',
541
            ']',
542
            '<',
543
            '>',
544
            '/',
545
            '+',
546
            '-',
547
            '_',
548
            '\\',
549
            '*',
550
        ];
551
        $replace_pattern = [
552
            ' ',
553
            ' ',
554
            ' ',
555
            ' ',
556
            ' ',
557
            ' ',
558
            ' ',
559
            ' ',
560
            '',
561
            '',
562
            '',
563
            '',
564
            '',
565
            '',
566
            '',
567
            '',
568
            '',
569
            '',
570
            '',
571
            '',
572
            '',
573
            '',
574
            '',
575
            '',
576
            '',
577
            '',
578
            '',
579
        ];
580
        $content         = \str_replace($search_pattern, $replace_pattern, $content);
581
        $keywords        = \explode(' ', $content);
582
        switch (\META_KEYWORDS_ORDER) {
583
            case 1:    // Returns keywords in the same order that they were created in the text
584
                $keywords = \array_unique($keywords);
585
                break;
586
            case 2:    // the keywords order is made according to the reverse keywords frequency (so the less frequent words appear in first in the list)
587
                $keywords = \array_count_values($keywords);
588
                \asort($keywords);
589
                $keywords = \array_keys($keywords);
590
                break;
591
            case 3:    // Same as previous, the only difference is that the most frequent words will appear in first in the list
592
                $keywords = \array_count_values($keywords);
593
                \arsort($keywords);
594
                $keywords = \array_keys($keywords);
595
                break;
596
        }
597
        foreach ($keywords as $keyword) {
598
            if (mb_strlen($keyword) >= $limit && !\is_numeric($keyword)) {
599
                $tmp[] = $keyword;
600
            }
601
        }
602
        $tmp = \array_slice($tmp, 0, $keywords_count);
603
        if (\count($tmp) > 0) {
604
            if (isset($xoTheme) && \is_object($xoTheme)) {
605
                $xoTheme->addMeta('meta', 'keywords', \implode(',', $tmp));
606
            } else {    // Compatibility for old Xoops versions
607
                $xoopsTpl->assign('xoops_meta_keywords', \implode(',', $tmp));
608
            }
609
        } else {
610
            if (!isset($configHandler) || !\is_object($configHandler)) {
611
                $configHandler = \xoops_getHandler('config');
612
            }
613
            $xoopsConfigMetaFooter = $configHandler->getConfigsByCat(\XOOPS_CONF_METAFOOTER);
614
            if (isset($xoTheme) && \is_object($xoTheme)) {
615
                $xoTheme->addMeta('meta', 'keywords', $xoopsConfigMetaFooter['meta_keywords']);
616
            } else {    // Compatibility for old Xoops versions
617
                $xoopsTpl->assign('xoops_meta_keywords', $xoopsConfigMetaFooter['meta_keywords']);
618
            }
619
        }
620
    }
621
622
    // Create meta description based on content
623
624
    /**
625
     * @param $content
626
     */
627
    public static function getMetaDescription($content)
628
    {
629
        global $xoopsTpl, $xoTheme;
630
        $myts    = \MyTextSanitizer::getInstance();
631
        $content = $myts->undoHtmlSpecialChars($myts->displayTarea($content));
632
        if (isset($xoTheme) && \is_object($xoTheme)) {
633
            $xoTheme->addMeta('meta', 'description', \strip_tags($content));
634
        } else {  // Compatibility for old Xoops versions
635
            $xoopsTpl->assign('xoops_meta_description', \strip_tags($content));
636
        }
637
    }
638
639
    // Create pagetitles
640
641
    /**
642
     * @param string $article
643
     * @param string $topic
644
     */
645
    public static function createPageTitle($article = '', $topic = '')
646
    {
647
        global $xoopsModule, $xoopsTpl;
648
        $myts    = \MyTextSanitizer::getInstance();
649
        $content = '';
650
        if (!empty($article)) {
651
            $content .= \strip_tags($myts->displayTarea($article));
652
        }
653
        if (!empty($topic)) {
654
            if ('' != \xoops_trim($content)) {
655
                $content .= ' - ' . \strip_tags($myts->displayTarea($topic));
656
            } else {
657
                $content .= \strip_tags($myts->displayTarea($topic));
658
            }
659
        }
660
        if (\is_object($xoopsModule) && '' != \xoops_trim($xoopsModule->name())) {
661
            if ('' != \xoops_trim($content)) {
662
                $content .= ' - ' . \strip_tags($myts->displayTarea($xoopsModule->name()));
663
            } else {
664
                $content .= \strip_tags($myts->displayTarea($xoopsModule->name()));
665
            }
666
        }
667
        if ('' != $content) {
668
            $xoopsTpl->assign('xoops_pagetitle', $content);
669
        }
670
    }
671
672
    // clear descriptions
673
674
    /**
675
     * @param $document
676
     * @return array|string|string[]|null
677
     */
678
    public static function convertHtml2text($document)
679
    {
680
        // PHP Manual:: function preg_replace $document should contain an HTML document.
681
        // This will remove HTML tags, javascript sections and white space. It will also
682
        // convert some common HTML entities to their text equivalent.
683
684
        $search = [
685
            "'<script[^>]*?>.*?</script>'si",  // Strip out javascript
686
            "'<[\/\!]*?[^<>]*?>'si",          // Strip out HTML tags
687
            "'([\r\n])[\s]+'",                // Strip out white space
688
            "'&(quot|#34);'i",                // Replace HTML entities
689
            "'&(amp|#38);'i",
690
            "'&(lt|#60);'i",
691
            "'&(gt|#62);'i",
692
            "'&(nbsp|#160);'i",
693
            "'&(iexcl|#161);'i",
694
            "'&(cent|#162);'i",
695
            "'&(pound|#163);'i",
696
            "'&(copy|#169);'i",
697
        ];
698
699
        $replace = [
700
            '',
701
            '',
702
            '\\1',
703
            '"',
704
            '&',
705
            '<',
706
            '>',
707
            ' ',
708
            \chr(161),
709
            \chr(162),
710
            \chr(163),
711
            \chr(169),
712
        ];
713
714
        $text = \preg_replace($search, $replace, $document);
715
716
        \preg_replace_callback(
717
            '/&#(\d+);/',
718
            static function ($matches) {
719
                return \chr($matches[1]);
720
            },
721
            $document
722
        );
723
724
        return $text;
725
    }
726
727
    //Retrieve moduleoptions equivalent to $Xoopsmoduleconfig
728
729
    /**
730
     * @param         $option
731
     * @param string  $repmodule
732
     * @return bool
733
     */
734
    public static function getModuleOption($option, $repmodule = 'lexikon')
735
    {
736
        global $xoopsModuleConfig, $xoopsModule;
737
        static $tbloptions = [];
738
        if (\is_array($tbloptions) && \array_key_exists($option, $tbloptions)) {
739
            return $tbloptions[$option];
740
        }
741
742
        $retval = false;
743
        if (isset($xoopsModuleConfig)
744
            && (\is_object($xoopsModule) && $xoopsModule->getVar('dirname') == $repmodule
745
                && $xoopsModule->getVar('isactive'))) {
746
            if (isset($xoopsModuleConfig[$option])) {
747
                $retval = $xoopsModuleConfig[$option];
748
            }
749
        } else {
750
            /** @var \XoopsModuleHandler $moduleHandler */
751
            $moduleHandler = \xoops_getHandler('module');
752
            $module        = $moduleHandler->getByDirname($repmodule);
753
            /** @var \XoopsConfigHandler $configHandler */
754
            $configHandler = \xoops_getHandler('config');
755
            if ($module) {
756
                $moduleConfig = $configHandler->getConfigsByCat(0, $module->getVar('mid'));
757
                if (isset($moduleConfig[$option])) {
758
                    $retval = $moduleConfig[$option];
759
                }
760
            }
761
        }
762
        $tbloptions[$option] = $retval;
763
764
        return $retval;
765
    }
766
767
    /**
768
     * Is Xoops 2.3.x ?
769
     *
770
     * @return bool need to say it ?
771
     */
772
    public static function isX23()
773
    {
774
        $x23 = false;
775
        $xv  = \str_replace('XOOPS ', '', \XOOPS_VERSION);
776
        if (mb_substr($xv, 2, 1) >= '3') {
777
            $x23 = true;
778
        }
779
780
        return $x23;
781
    }
782
783
    /**
784
     * Retreive an editor according to the module's option "form_options"
785
     * following function is from News modified by trabis
786
     * @param                                                                                                                                 $caption
787
     * @param                                                                                                                                 $name
788
     * @param string                                                                                                                          $value
789
     * @param string                                                                                                                          $width
790
     * @param string                                                                                                                          $height
791
     * @param string                                                                                                                          $supplemental
792
     * @return bool|\XoopsFormEditor
793
     */
794
    public static function getWysiwygForm($caption, $name, $value = '', $width = '100%', $height = '400px', $supplemental = '')
795
    {
796
        $editor_option            = mb_strtolower(static::getModuleOption('form_options'));
797
        $editor                   = false;
798
        $editor_configs           = [];
799
        $editor_configs['name']   = $name;
800
        $editor_configs['value']  = $value;
801
        $editor_configs['rows']   = 35;
802
        $editor_configs['cols']   = 60;
803
        $editor_configs['width']  = '100%';
804
        $editor_configs['height'] = '350px';
805
        $editor_configs['editor'] = $editor_option;
806
807
        if (static::isX23()) {
808
            $editor = new \XoopsFormEditor($caption, $name, $editor_configs);
809
810
            return $editor;
811
        }
812
813
        // Only for Xoops 2.0.x
814
        switch ($editor_option) {
815
            case 'htmlarea':
816
                if (\is_readable(XOOPS_ROOT_PATH . '/class/htmlarea/formhtmlarea.php')) {
817
                    require_once XOOPS_ROOT_PATH . '/class/htmlarea/formhtmlarea.php';
818
                    $editor = new \XoopsFormHtmlarea($caption, $name, $value);
819
                }
820
                break;
821
            case 'dhtmltextarea':
822
            case 'dhtml':
823
                $editor = new \XoopsFormDhtmlTextArea($caption, $name, $value, 10, 50, $supplemental);
824
                break;
825
            case 'textarea':
826
                $editor = new \XoopsFormTextArea($caption, $name, $value);
827
                break;
828
            case 'tinyeditor':
829
            case 'tinymce':
830
                if (\is_readable(XOOPS_ROOT_PATH . '/class/xoopseditor/tinyeditor/formtinyeditortextarea.php')) {
831
                    require_once XOOPS_ROOT_PATH . '/class/xoopseditor/tinyeditor/formtinyeditortextarea.php';
832
                    $editor = new \XoopsFormTinyeditorTextArea(
833
                        [
834
                            'caption' => $caption,
835
                            'name'    => $name,
836
                            'value'   => $value,
837
                            'width'   => '100%',
838
                            'height'  => '400px',
839
                        ]
840
                    );
841
                }
842
                break;
843
        }
844
845
        return $editor;
846
    }
847
848
    /**
849
     * @param \Xmf\Module\Helper $helper
850
     * @param array|null         $options
851
     * @return \XoopsFormDhtmlTextArea|\XoopsFormEditor
852
     */
853
    public static function getEditor($helper = null, $options = null)
854
    {
855
856
        if (null === $options) {
857
            $options           = [];
858
            $options['name']   = 'Editor';
859
            $options['value']  = 'Editor';
860
            $options['rows']   = 10;
861
            $options['cols']   = '100%';
862
            $options['width']  = '100%';
863
            $options['height'] = '400px';
864
        }
865
866
        if (null === $helper) {
867
            $helper = Helper::getInstance();
868
        }
869
870
        $isAdmin = $helper->isUserAdmin();
871
872
        if (\class_exists('XoopsFormEditor')) {
873
            if ($isAdmin) {
874
                $descEditor = new \XoopsFormEditor(\ucfirst($options['name']), $helper->getConfig('editorAdmin'), $options, $nohtml = false, $onfailure = 'textarea');
875
            } else {
876
                $descEditor = new \XoopsFormEditor(\ucfirst($options['name']), $helper->getConfig('editorUser'), $options, $nohtml = false, $onfailure = 'textarea');
877
            }
878
        } else {
879
            $descEditor = new \XoopsFormDhtmlTextArea(\ucfirst($options['name']), $options['name'], $options['value'], '100%', '100%');
880
        }
881
882
        //        $form->addElement($descEditor);
883
884
        return $descEditor;
885
    }
886
887
    /**
888
     * linkterms: assign module header
889
     *
890
     * tooltips (c) dhtmlgoodies
891
     */
892
    public static function getModuleHeader()
893
    {
894
        global $xoopsTpl, $xoTheme, $xoopsModule, $lexikon_module_header;
895
896
        $helper = Helper::getInstance();
897
898
        if (isset($xoTheme) && \is_object($xoTheme)) {
899
            $xoTheme->addStylesheet('modules/lexikon/assets/css/style.css');
900
            if (3 == $helper->getConfig('linkterms')) {
901
                $xoTheme->addStylesheet('modules/lexikon/assets/css/linkterms.css');
902
                $xoTheme->addScript('/modules/lexikon/assets/js/tooltipscript2.js', ['type' => 'text/javascript']);
903
            }
904
            if (4 == $helper->getConfig('linkterms')) {
905
                $xoTheme->addScript('/modules/lexikon/assets/js/popup.js', ['type' => 'text/javascript']);
906
            }
907
            if (5 == $helper->getConfig('linkterms')) {
908
                $xoTheme->addStylesheet('modules/lexikon/assets/css/linkterms.css');
909
                $xoTheme->addScript('/modules/lexikon/assets/js/balloontooltip.js', ['type' => 'text/javascript']);
910
            }
911
            if (6 == $helper->getConfig('linkterms')) {
912
                $xoTheme->addStylesheet('modules/lexikon/assets/css/linkterms.css');
913
                $xoTheme->addScript('/modules/lexikon/assets/js/shadowtooltip.js', ['type' => 'text/javascript']);
914
            }
915
        } else {
916
            $lexikon_url = XOOPS_URL . '/modules/' . $xoopsModule->getVar('dirname');
917
            if (3 == $helper->getConfig('linkterms')) {
918
                $lexikon_module_header = '<link rel="stylesheet" type="text/css" href="assets/css/style.css" >
919
            <link rel="stylesheet" type="text/css" href="assets/css/linkterms.css" >
920
            <script src="' . $lexikon_url . '/assets/js/tooltipscript2.js" type="text/javascript"></script>';
921
            }
922
            if (4 == $helper->getConfig('linkterms')) {
923
                $lexikon_module_header = '<link rel="stylesheet" type="text/css" href="assets/css/style.css" >
924
            <link rel="stylesheet" type="text/css" href="assets/css/linkterms.css" >
925
            <script src="' . $lexikon_url . '/assets/js/popup.js" type="text/javascript"></script>';
926
            }
927
            if (5 == $helper->getConfig('linkterms')) {
928
                $lexikon_module_header = '<link rel="stylesheet" type="text/css" href="assets/css/style.css" >
929
            <link rel="stylesheet" type="text/css" href="assets/css/linkterms.css" >
930
            <script src="' . $lexikon_url . '/assets/js/balloontooltip.js" type="text/javascript"></script>';
931
            }
932
            if (6 == $helper->getConfig('linkterms')) {
933
                $lexikon_module_header = '<link rel="stylesheet" type="text/css" href="assets/css/style.css" >
934
            <link rel="stylesheet" type="text/css" href="assets/css/linkterms.css" >
935
            <script src="' . $lexikon_url . '/assets/js/shadowtooltip.js" type="text/javascript"></script>';
936
            }
937
        }
938
    }
939
940
    /**
941
     * Validate userid
942
     * @param $uids
943
     * @return bool
944
     */
945
    public static function getUserData($uids)
946
    {
947
        global $xoopsDB, $xoopsUser, $xoopsUserIsAdmin;
948
949
        if ($uids <= 0) {
950
            return false;
951
        }
952
        if ($uids > 0) {
953
            $memberHandler = \xoops_getHandler('member');
954
            $user          = $memberHandler->getUser($uids);
955
            if (!\is_object($user)) {
956
                return false;
957
            }
958
        }
959
        $result = $xoopsDB->query('SELECT * FROM ' . $xoopsDB->prefix('users') . " WHERE uid='$uids'");
960
        if ($xoopsDB->getRowsNum($result) <= 0) {
961
            return false;
962
        }
963
        $row = $xoopsDB->fetchArray($result);
964
965
        return $row;
966
    }
967
968
    // Get all terms published by an author
969
970
    /**
971
     * @param $uid
972
     */
973
    public static function getAuthorProfile($uid)
974
    {
975
        require_once XOOPS_ROOT_PATH . '/class/pagenav.php';
976
        global $authortermstotal, $xoopsTpl, $xoopsDB, $xoopsUser;
977
978
        $helper = Helper::getInstance();
979
        $myts   = \MyTextSanitizer::getInstance();
980
        //permissions
981
        $grouppermHandler = \xoops_getHandler('groupperm');
982
        $groups           = \is_object($xoopsUser) ? $xoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;
983
        /** @var \XoopsModuleHandler $moduleHandler */
984
        $moduleHandler = \xoops_getHandler('module');
985
        $module        = $moduleHandler->getByDirname('lexikon');
986
        $module_id     = $module->getVar('mid');
987
        $allowed_cats  = $grouppermHandler->getItemIds('lexikon_view', $groups, $module_id);
988
        $catids        = \implode(',', $allowed_cats);
989
        $catperms      = " AND categoryID IN ($catids) ";
990
991
        $start = \Xmf\Request::getInt('start', 0, 'GET');
992
        $limit = $helper->getConfig('indexperpage');
993
994
        $sql = $xoopsDB->query(
995
            'SELECT *
996
                              FROM ' . $xoopsDB->prefix('lxentries') . "
997
                              WHERE uid='" . (int)$uid . "' AND  offline = '0' AND submit = '0' AND request = '0' " . $catperms . "
998
                              ORDER BY term
999
                              LIMIT $start,$limit"
1000
        );
1001
1002
        while (false !== ($row = $xoopsDB->fetchArray($sql))) {
1003
            $xoopsTpl->append(
1004
                'entries',
1005
                [
1006
                    'id'      => $row['entryID'],
1007
                    'name'    => $row['term'],
1008
                    'date'    => \date($helper->getConfig('dateformat'), $row['datesub']),
1009
                    'counter' => $row['counter'],
1010
                ]
1011
            );
1012
        }
1013
1014
        $navstring                = '';
1015
        $navstring                .= 'uid=' . $uid . '&start';
1016
        $pagenav                  = new \XoopsPageNav($authortermstotal, $helper->getConfig('indexperpage'), $start, $navstring);
1017
        $authortermsarr['navbar'] = '<span style="text-align:right;">' . $pagenav->renderNav(6) . '</span>';
1018
        $xoopsTpl->assign('authortermsarr', $authortermsarr);
1019
    }
1020
1021
    // Returns the author's IDs for authorslist
1022
1023
    /**
1024
     * @param int $limit
1025
     * @param int $start
1026
     * @return array
1027
     */
1028
    public static function getAuthors($limit = 0, $start = 0)
1029
    {
1030
        global $xoopsDB;
1031
1032
        $ret    = [];
1033
        $sql    = 'SELECT DISTINCT(uid) AS uid FROM ' . $xoopsDB->prefix('lxentries') . ' WHERE offline = 0 ';
1034
        $sql    .= ' ORDER BY uid';
1035
        $result = $xoopsDB->query($sql);
1036
        while (false !== ($myrow = $xoopsDB->fetchArray($result))) {
1037
            $ret[] = $myrow['uid'];
1038
        }
1039
1040
        return $ret;
1041
    }
1042
1043
    // link to userprofile
1044
1045
    /**
1046
     * @param $userid
1047
     * @return string
1048
     */
1049
    public static function getLinkedProfileFromId($userid)
1050
    {
1051
        global $uid, $xoopsModule;
1052
        $userid = (int)$uid;
1053
        if ($userid > 0) {
1054
            $memberHandler = \xoops_getHandler('member');
1055
            $user          = $memberHandler->getUser($userid);
1056
            if (\is_object($user)) {
1057
                $linkeduser = '<A TITLE="' . _MD_LEXIKON_AUTHORPROFILETEXT . '" HREF="' . XOOPS_URL . '/modules/' . $xoopsModule->dirname() . '/profile.php?uid=' . $uid . '">' . $user->getVar('uname') . '</a>';
1058
                //$linkeduser = \XoopsUserUtility::getUnameFromId ( $uid );
1059
                //$linkeduser .= '<div style=\'position:relative; right: 4px; top: 2px;\'><A TITLE="'._MD_LEXIKON_AUTHORPROFILETEXT.'" HREF="'.XOOPS_URL.'/modules/'.$xoopsModule->dirname().'/profile.php?uid='.$uid.'">'._MD_LEXIKON_AUTHORPROFILETEXT.'</a></div>';
1060
                return $linkeduser;
1061
            }
1062
        }
1063
1064
        return $GLOBALS['xoopsConfig']['anonymous'];
1065
    }
1066
1067
    // functionset to assign terms with accentuated or umlaut initials to the adequate initial
1068
1069
    /**
1070
     * @param $string
1071
     * @return array|string|string[]
1072
     */
1073
    public static function removeAccents($string)
1074
    {
1075
        $chars['in']  = \chr(128)
1076
                        . \chr(131)
1077
                        . \chr(138)
1078
                        . \chr(142)
1079
                        . \chr(154)
1080
                        . \chr(158)
1081
                        . \chr(159)
1082
                        . \chr(162)
1083
                        . \chr(165)
1084
                        . \chr(181)
1085
                        . \chr(192)
1086
                        . \chr(193)
1087
                        . \chr(194)
1088
                        . \chr(195)
1089
                        . \chr(196)
1090
                        . \chr(197)
1091
                        . \chr(199)
1092
                        . \chr(200)
1093
                        . \chr(201)
1094
                        . \chr(202)
1095
                        . \chr(203)
1096
                        . \chr(204)
1097
                        . \chr(205)
1098
                        . \chr(206)
1099
                        . \chr(207)
1100
                        . \chr(209)
1101
                        . \chr(210)
1102
                        . \chr(211)
1103
                        . \chr(212)
1104
                        . \chr(213)
1105
                        . \chr(214)
1106
                        . \chr(216)
1107
                        . \chr(217)
1108
                        . \chr(218)
1109
                        . \chr(219)
1110
                        . \chr(220)
1111
                        . \chr(221)
1112
                        . \chr(224)
1113
                        . \chr(225)
1114
                        . \chr(226)
1115
                        . \chr(227)
1116
                        . \chr(228)
1117
                        . \chr(229)
1118
                        . \chr(231)
1119
                        . \chr(232)
1120
                        . \chr(233)
1121
                        . \chr(234)
1122
                        . \chr(235)
1123
                        . \chr(236)
1124
                        . \chr(237)
1125
                        . \chr(238)
1126
                        . \chr(239)
1127
                        . \chr(241)
1128
                        . \chr(242)
1129
                        . \chr(243)
1130
                        . \chr(244)
1131
                        . \chr(245)
1132
                        . \chr(246)
1133
                        . \chr(248)
1134
                        . \chr(249)
1135
                        . \chr(250)
1136
                        . \chr(251)
1137
                        . \chr(252)
1138
                        . \chr(253)
1139
                        . \chr(255);
1140
        $chars['out'] = 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy';
1141
        if (static::isUtf8($string)) {
1142
            $invalid_latin_chars = [
1143
                \chr(197) . \chr(146)             => 'OE',
1144
                \chr(197) . \chr(147)             => 'oe',
1145
                \chr(197) . \chr(160)             => 'S',
1146
                \chr(197) . \chr(189)             => 'Z',
1147
                \chr(197) . \chr(161)             => 's',
1148
                \chr(197) . \chr(190)             => 'z',
1149
                \chr(226) . \chr(130) . \chr(172) => 'E',
1150
            ];
1151
            $string              = utf8_decode(strtr($string, $invalid_latin_chars));
1152
        }
1153
        $string              = strtr($string, $chars['in'], $chars['out']);
1154
        $double_chars['in']  = [
1155
            \chr(140),
1156
            \chr(156),
1157
            \chr(198),
1158
            \chr(208),
1159
            \chr(222),
1160
            \chr(223),
1161
            \chr(230),
1162
            \chr(240),
1163
            \chr(254),
1164
        ];
1165
        $double_chars['out'] = ['OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'];
1166
        $string              = \str_replace($double_chars['in'], $double_chars['out'], $string);
1167
1168
        return $string;
1169
    }
1170
1171
    /**
1172
     * @param $Str
1173
     * @return bool
1174
     */
1175
    public static function isUtf8($Str)
1176
    { # by bmorel at ssi dot fr
1177
        for ($i = 0, $iMax = mb_strlen($Str); $i < $iMax; ++$i) {
1178
            if (\ord($Str[$i]) < 0x80) {
1179
                continue;
1180
            }
1181
1182
            if (0xC0 == (\ord($Str[$i]) & 0xE0)) {
1183
                $n = 1;
1184
            } # 0bbbbbbb
1185
            # 110bbbbb
1186
            elseif (0xE0 == (\ord($Str[$i]) & 0xF0)) {
1187
                $n = 2;
1188
            } # 1110bbbb
1189
            elseif (0xF0 == (\ord($Str[$i]) & 0xF8)) {
1190
                $n = 3;
1191
            } # 11110bbb
1192
            elseif (0xF8 == (\ord($Str[$i]) & 0xFC)) {
1193
                $n = 4;
1194
            } # 111110bb
1195
            elseif (0xFC == (\ord($Str[$i]) & 0xFE)) {
1196
                $n = 5;
1197
            } # 1111110b
1198
            else {
1199
                return false;
1200
            } # Does not match any model
1201
            for ($j = 0; $j < $n; ++$j) { # n bytes matching 10bbbbbb follow ?
1202
                if ((++$i == mb_strlen($Str)) || (0x80 != (\ord($Str[$i]) & 0xC0))) {
1203
                    return false;
1204
                }
1205
            }
1206
        }
1207
1208
        return true;
1209
    }
1210
1211
    /**
1212
     * @param $field
1213
     * @return string
1214
     */
1215
    public static function sanitizeFieldName($field)
1216
    {
1217
        $field = static::removeAccents($field);
1218
        $field = mb_strtolower($field);
1219
        $field = \preg_replace('/&.+?;/', '', $field); // kill entities
1220
        $field = \preg_replace('/[^a-z0-9 _-]/', '', $field);
1221
        $field = \preg_replace('/\s+/', ' ', $field);
1222
        $field = \str_replace(' ', '-', $field);
1223
        $field = \preg_replace('|-+|', '-', $field);
1224
        $field = \trim($field, '-');
1225
1226
        return $field;
1227
    }
1228
1229
    // Verify that a term does not exist for submissions and requests (both user frontend and admin backend)
1230
1231
    /**
1232
     * @param $term
1233
     * @param $table
1234
     * @return mixed
1235
     */
1236
    public static function isTermPresent($term, $table)
1237
    {
1238
        global $xoopsDB;
1239
        $sql    = \sprintf('SELECT COUNT(*) FROM `%s` WHERE term = %s', $table, $xoopsDB->quoteString(\addslashes($term)));
1240
        $result = $xoopsDB->query($sql);
1241
        [$count] = $xoopsDB->fetchRow($result);
1242
1243
        return $count;
1244
    }
1245
1246
    // Static method to get author data block authors - from AMS
1247
1248
    /**
1249
     * @param int    $limit
1250
     * @param string $sort
1251
     * @param string $name
1252
     * @param string $compute_method
1253
     * @return array|bool
1254
     */
1255
    public static function getBlockAuthors($limit = 5, $sort = 'count', $name = 'uname', $compute_method = 'average')
1256
    {
1257
        $limit = (int)$limit;
1258
        if ('uname' !== $name) {
1259
            $name = 'name';
1260
        } //making sure that there is not invalid information in field value
1261
        $ret = [];
1262
        $db  = \XoopsDatabaseFactory::getDatabaseConnection();
1263
        if ('count' === $sort) {
1264
            $sql = 'SELECT u.' . $name . ' AS name, u.uid , count( n.entryID ) AS count
1265
              FROM ' . $db->prefix('users') . ' u, ' . $db->prefix('lxentries') . ' n
1266
              WHERE u.uid = n.uid
1267
              AND n.datesub > 0 AND n.datesub <= ' . \time() . ' AND n.offline = 0 AND n.submit = 0
1268
              GROUP BY u.uid ORDER BY count DESC';
1269
        } elseif ('read' === $sort) {
1270
            if ('average' === $compute_method) {
1271
                $compute = 'sum( n.counter ) / count( n.entryID )';
1272
            } else {
1273
                $compute = 'sum( n.counter )';
1274
            }
1275
            $sql = 'SELECT u.' . $name . " AS name, u.uid , $compute AS count
1276
              FROM " . $db->prefix('users') . ' u, ' . $db->prefix('lxentries') . ' n
1277
              WHERE u.uid = n.uid
1278
              AND n.datesub > 0 AND n.datesub <= ' . \time() . ' AND n.offline = 0 AND n.submit = 0
1279
              GROUP BY u.uid ORDER BY count DESC';
1280
        }
1281
        if (!$result = $db->query($sql, $limit)) {
1282
            return false;
1283
        }
1284
1285
        while (false !== ($row = $db->fetchArray($result))) {
1286
            if ('name' === $name && '' == $row['name']) {
1287
                $row['name'] = \XoopsUser::getUnameFromId($row['uid']);
1288
            }
1289
            $row['count'] = \round($row['count'], 0);
1290
            $ret[]        = $row;
1291
        }
1292
1293
        return $ret;
1294
    }
1295
1296
    /**
1297
     * close all unclosed xhtml tags *Test*
1298
     *
1299
     * @param string $html
1300
     * @return string
1301
     * @author Milian Wolff <mail -at- milianw.de>
1302
     */
1303
    public static function closeTags2($html)
1304
    {
1305
        // put all opened tags into an array
1306
        \preg_match_all('#<([a-z]+)( .*)?(?!/)>#iU', $html, $result);
1307
        $openedtags = $result[1];
1308
1309
        // put all closed tags into an array
1310
        \preg_match_all('#</([a-z]+)>#iU', $html, $result);
1311
        $closedtags = $result[1];
1312
        $len_opened = \count($openedtags);
1313
        // all tags are closed
1314
        if (\count($closedtags) == $len_opened) {
1315
            return $html;
1316
        }
1317
1318
        $openedtags = \array_reverse($openedtags);
1319
        // close tags
1320
        for ($i = 0; $i < $len_opened; ++$i) {
1321
            if (!\in_array($openedtags[$i], $closedtags)) {
1322
                $html .= '</' . $openedtags[$i] . '>';
1323
            } else {
1324
                unset($closedtags[\array_search($openedtags[$i], $closedtags, true)]);
1325
            }
1326
        }
1327
1328
        return $html;
1329
    }
1330
1331
    /**
1332
     * @param $string
1333
     * @return string
1334
     * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
1335
     *           <amos dot robinson at gmail dot com>
1336
     */
1337
    public static function closeTags($string)
1338
    {
1339
        // match opened tags
1340
        if (\preg_match_all('/<([a-z\:\-]+)[^\/]>/', $string, $start_tags)) {
1341
            $start_tags = $start_tags[1];
1342
            // match closed tags
1343
            if (\preg_match_all('/<\/([a-z]+)>/', $string, $end_tags)) {
1344
                $complete_tags = [];
1345
                $end_tags      = $end_tags[1];
1346
1347
                foreach ($start_tags as $key => $val) {
1348
                    $posb = \array_search($val, $end_tags, true);
1349
                    if (\is_int($posb)) {
1350
                        unset($end_tags[$posb]);
1351
                    } else {
1352
                        $complete_tags[] = $val;
1353
                    }
1354
                }
1355
            } else {
1356
                $complete_tags = $start_tags;
1357
            }
1358
1359
            $complete_tags = \array_reverse($complete_tags);
1360
            for ($i = 0, $iMax = \count($complete_tags); $i < $iMax; ++$i) {
1361
                $string .= '</' . $complete_tags[$i] . '>';
1362
            }
1363
        }
1364
1365
        return $string;
1366
    }
1367
1368
    /**
1369
     * Smarty plugin
1370
     * @param mixed $string
1371
     * @param mixed $length
1372
     * @param mixed $etc
1373
     * @param mixed $break_words
1374
     * @package    Smarty
1375
     * @subpackage plugins
1376
     */
1377
1378
    /**
1379
     * Smarty truncate_tagsafe modifier plugin
1380
     *
1381
     * Type:     modifier<br>
1382
     * Name:     truncate_tagsafe<br>
1383
     * Purpose:  Truncate a string to a certain length if necessary,
1384
     *           optionally splitting in the middle of a word, and
1385
     *           appending the $etc string or inserting $etc into the middle.
1386
     *           Makes sure no tags are left half-open or half-closed (e.g. "Banana in a <a...")
1387
     * @param               $string
1388
     * @param int           $length
1389
     * @param string        $etc
1390
     * @param bool          $break_words
1391
     * @return string
1392
     * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
1393
     *           <amos dot robinson at gmail dot com>
1394
     *           used in Block entries_scrolling.php
1395
     */
1396
    public static function truncateTagSafe($string, $length = 80, $etc = '...', $break_words = false)
1397
    {
1398
        if (0 == $length) {
1399
            return '';
1400
        }
1401
        if (mb_strlen($string) > $length) {
1402
            $length -= mb_strlen($etc);
1403
            if (!$break_words) {
1404
                $string = \preg_replace('/\s+?(\S+)?$/', '', mb_substr($string, 0, $length + 1));
1405
                $string = \preg_replace('/<[^>]*$/', '', $string);
1406
                $string = static::closeTags($string);
1407
            }
1408
1409
            return $string . $etc;
1410
        }
1411
1412
        return $string;
1413
    }
1414
1415
    /**
1416
     * @return array
1417
     */
1418
    public static function getSummary()
1419
    {
1420
        global $xoopsDB;
1421
1422
        $summary = [];
1423
1424
        $result01 = $xoopsDB->query(
1425
            'SELECT COUNT(*)
1426
                                   FROM ' . $xoopsDB->prefix('lxcategories') . ' '
1427
        );
1428
        [$totalcategories] = $xoopsDB->fetchRow($result01);
1429
1430
        $result02 = $xoopsDB->query(
1431
            'SELECT COUNT(*)
1432
                                   FROM ' . $xoopsDB->prefix('lxentries') . '
1433
                                   WHERE submit = 0'
1434
        );
1435
        [$totalpublished] = $xoopsDB->fetchRow($result02);
1436
1437
        $result03 = $xoopsDB->query(
1438
            'SELECT COUNT(*)
1439
                                   FROM ' . $xoopsDB->prefix('lxentries') . "
1440
                                   WHERE submit = '1' AND request = '0' "
1441
        );
1442
        [$totalsubmitted] = $xoopsDB->fetchRow($result03);
1443
1444
        $result04 = $xoopsDB->query(
1445
            'SELECT COUNT(*)
1446
                                   FROM ' . $xoopsDB->prefix('lxentries') . "
1447
                                   WHERE submit = '1' AND request = '1' "
1448
        );
1449
        [$totalrequested] = $xoopsDB->fetchRow($result04);
1450
1451
        // Recuperer les valeurs dans la base de donnees
1452
1453
        $summary['publishedEntries']    = $totalpublished ?: '0';
1454
        $summary['availableCategories'] = $totalcategories ?: '0';
1455
        $summary['submittedEntries']    = $totalsubmitted ?: '0';
1456
        $summary['requestedEntries']    = $totalrequested ?: '0';
1457
1458
        //print_r($summary);
1459
        return $summary;
1460
    }
1461
1462
    // end function
1463
1464
    /**
1465
     * @param $text
1466
     * @param $form_sort
1467
     * @return string
1468
     */
1469
    public static function selectSorting($text, $form_sort)
1470
    {
1471
        global $start, $order, $file_cat, $sort, $xoopsModule;
1472
1473
        $select_view   = '';
1474
        $moduleDirName = \basename(\dirname(__DIR__));
1475
1476
        $helper = Helper::getInstance();
1477
1478
        $pathModIcon16 = XOOPS_URL . '/modules/' . $moduleDirName . '/' . $helper->getModule()->getInfo('modicons16');
1479
1480
        $select_view = '<form name="form_switch" id="form_switch" action="' . Request::getString('REQUEST_URI', '', 'SERVER') . '" method="post"><span style="font-weight: bold;">' . $text . '</span>';
1481
        //$sorts =  $sort ==  'asc' ? 'desc' : 'asc';
1482
        if ($form_sort == $sort) {
1483
            $sel1 = 'asc' === $order ? 'selasc.png' : 'asc.png';
1484
            $sel2 = 'desc' === $order ? 'seldesc.png' : 'desc.png';
1485
        } else {
1486
            $sel1 = 'asc.png';
1487
            $sel2 = 'desc.png';
1488
        }
1489
        $select_view .= '  <a href="' . Request::getString('SCRIPT_NAME', '', 'SERVER') . '?start=' . $start . '&sort=' . $form_sort . '&order=asc" ><img src="' . $pathModIcon16 . '/' . $sel1 . '" title="ASC" alt="ASC"></a>';
1490
        $select_view .= '<a href="' . Request::getString('SCRIPT_NAME', '', 'SERVER') . '?start=' . $start . '&sort=' . $form_sort . '&order=desc" ><img src="' . $pathModIcon16 . '/' . $sel2 . '" title="DESC" alt="DESC"></a>';
1491
        $select_view .= '</form>';
1492
1493
        return $select_view;
1494
    }
1495
1496
    /***************Blocks***************/
1497
1498
    /**
1499
     * @param array $cats
1500
     * @return string
1501
     */
1502
    public static function block_addCatSelect($cats)
1503
    {
1504
        $cat_sql = '';
1505
        if (\is_array($cats)) {
1506
            $cat_sql = '(' . \current($cats);
1507
            \array_shift($cats);
1508
            foreach ($cats as $cat) {
1509
                $cat_sql .= ',' . $cat;
1510
            }
1511
            $cat_sql .= ')';
1512
        }
1513
1514
        return $cat_sql;
1515
    }
1516
1517
    /**
1518
     * @param $content
1519
     */
1520
    public static function meta_keywords($content)
1521
    {
1522
        global $xoopsTpl, $xoTheme;
1523
        $myts    = \MyTextSanitizer::getInstance();
1524
        $content = $myts->undoHtmlSpecialChars($myts->displayTarea($content));
1525
        if (null !== $xoTheme && \is_object($xoTheme)) {
1526
            $xoTheme->addMeta('meta', 'keywords', \strip_tags($content));
1527
        } else {    // Compatibility for old Xoops versions
1528
            $xoopsTpl->assign('xoops_meta_keywords', \strip_tags($content));
1529
        }
1530
    }
1531
1532
    /**
1533
     * @param $content
1534
     */
1535
    public static function meta_description($content)
1536
    {
1537
        global $xoopsTpl, $xoTheme;
1538
        $myts    = \MyTextSanitizer::getInstance();
1539
        $content = $myts->undoHtmlSpecialChars($myts->displayTarea($content));
1540
        if (null !== $xoTheme && \is_object($xoTheme)) {
1541
            $xoTheme->addMeta('meta', 'description', \strip_tags($content));
1542
        } else {    // Compatibility for old Xoops versions
1543
            $xoopsTpl->assign('xoops_meta_description', \strip_tags($content));
1544
        }
1545
    }
1546
1547
    /**
1548
     * @param $tableName
1549
     * @param $columnName
1550
     *
1551
     * @return array
1552
     */
1553
    public static function enumerate($tableName, $columnName)
1554
    {
1555
        $table = $GLOBALS['xoopsDB']->prefix($tableName);
1556
1557
        //    $result = $GLOBALS['xoopsDB']->query("SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
1558
        //        WHERE TABLE_NAME = '" . $table . "' AND COLUMN_NAME = '" . $columnName . "'")
1559
        //    || exit ($GLOBALS['xoopsDB']->error());
1560
1561
        $sql    = 'SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = "' . $table . '" AND COLUMN_NAME = "' . $columnName . '"';
1562
        $result = $GLOBALS['xoopsDB']->query($sql);
1563
        if (!$result) {
1564
            exit($GLOBALS['xoopsDB']->error());
1565
        }
1566
1567
        $row      = $GLOBALS['xoopsDB']->fetchBoth($result);
1568
        $enumList = \explode(',', \str_replace("'", '', mb_substr($row['COLUMN_TYPE'], 5, -6)));
1569
1570
        return $enumList;
1571
    }
1572
1573
    /**
1574
     * @param array|string $tableName
1575
     * @param string       $id_field
1576
     * @param int          $id
1577
     *
1578
     * @return false|void
1579
     */
1580
    public static function cloneRecord($tableName, $id_field, $id)
1581
    {
1582
        $new_id = false;
1583
        $table  = $GLOBALS['xoopsDB']->prefix($tableName);
1584
        // copy content of the record you wish to clone
1585
        $tempTable = $GLOBALS['xoopsDB']->fetchArray($GLOBALS['xoopsDB']->query("SELECT * FROM $table WHERE $id_field='$id' "), \MYSQLI_ASSOC) || exit('Could not select record');
1586
        // set the auto-incremented id's value to blank.
1587
        unset($tempTable[$id_field]);
1588
        // insert cloned copy of the original  record
1589
        $result = $GLOBALS['xoopsDB']->queryF("INSERT INTO $table (" . \implode(', ', \array_keys($tempTable)) . ") VALUES ('" . \implode("', '", $tempTable) . "')") || exit($GLOBALS['xoopsDB']->error());
1590
1591
        if ($result) {
1592
            // Return the new id
1593
            $new_id = $GLOBALS['xoopsDB']->getInsertId();
1594
        }
1595
1596
        return $new_id;
1597
    }
1598
1599
    /**
1600
     * truncateHtml can truncate a string up to a number of characters while preserving whole words and HTML tags
1601
     * www.gsdesign.ro/blog/cut-html-string-without-breaking-the-tags
1602
     * www.cakephp.org
1603
     *
1604
     * @param string $text         String to truncate.
1605
     * @param int    $length       Length of returned string, including ellipsis.
1606
     * @param string $ending       Ending to be appended to the trimmed string.
1607
     * @param bool   $exact        If false, $text will not be cut mid-word
1608
     * @param bool   $considerHtml If true, HTML tags would be handled correctly
1609
     *
1610
     * @return string Trimmed string.
1611
     */
1612
    public static function truncateHtml($text, $length = 100, $ending = '...', $exact = false, $considerHtml = true)
1613
    {
1614
        if ($considerHtml) {
1615
            // if the plain text is shorter than the maximum length, return the whole text
1616
            if (mb_strlen(\preg_replace('/<.*?' . '>/', '', $text)) <= $length) {
1617
                return $text;
1618
            }
1619
            // splits all html-tags to scanable lines
1620
            \preg_match_all('/(<.+?' . '>)?([^<>]*)/s', $text, $lines, \PREG_SET_ORDER);
1621
            $total_length = mb_strlen($ending);
1622
            $open_tags    = [];
1623
            $truncate     = '';
1624
            foreach ($lines as $line_matchings) {
1625
                // if there is any html-tag in this line, handle it and add it (uncounted) to the output
1626
                if (!empty($line_matchings[1])) {
1627
                    // if it's an "empty element" with or without xhtml-conform closing slash
1628
                    if (\preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $line_matchings[1])) {
1629
                        // do nothing
1630
                        // if tag is a closing tag
1631
                    } elseif (\preg_match('/^<\s*\/(\S+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {
1632
                        // delete tag from $open_tags list
1633
                        $pos = \array_search($tag_matchings[1], $open_tags, true);
1634
                        if (false !== $pos) {
1635
                            unset($open_tags[$pos]);
1636
                        }
1637
                        // if tag is an opening tag
1638
                    } elseif (\preg_match('/^<\s*([^\s>!]+).*?' . '>$/s', $line_matchings[1], $tag_matchings)) {
1639
                        // add tag to the beginning of $open_tags list
1640
                        \array_unshift($open_tags, mb_strtolower($tag_matchings[1]));
1641
                    }
1642
                    // add html-tag to $truncate'd text
1643
                    $truncate .= $line_matchings[1];
1644
                }
1645
                // calculate the length of the plain text part of the line; handle entities as one character
1646
                $content_length = mb_strlen(\preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
1647
                if ($total_length + $content_length > $length) {
1648
                    // the number of characters which are left
1649
                    $left            = $length - $total_length;
1650
                    $entities_length = 0;
1651
                    // search for html entities
1652
                    if (\preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', $line_matchings[2], $entities, \PREG_OFFSET_CAPTURE)) {
1653
                        // calculate the real length of all entities in the legal range
1654
                        foreach ($entities[0] as $entity) {
1655
                            if ($left >= $entity[1] + 1 - $entities_length) {
1656
                                $left--;
1657
                                $entities_length += mb_strlen($entity[0]);
1658
                            } else {
1659
                                // no more characters left
1660
                                break;
1661
                            }
1662
                        }
1663
                    }
1664
                    $truncate .= mb_substr($line_matchings[2], 0, $left + $entities_length);
1665
                    // maximum lenght is reached, so get off the loop
1666
                    break;
1667
                }
1668
                $truncate     .= $line_matchings[2];
1669
                $total_length += $content_length;
1670
1671
                // if the maximum length is reached, get off the loop
1672
                if ($total_length >= $length) {
1673
                    break;
1674
                }
1675
            }
1676
        } else {
1677
            if (mb_strlen($text) <= $length) {
1678
                return $text;
1679
            }
1680
            $truncate = mb_substr($text, 0, $length - mb_strlen($ending));
1681
        }
1682
        // if the words shouldn't be cut in the middle...
1683
        if (!$exact) {
1684
            // ...search the last occurance of a space...
1685
            $spacepos = mb_strrpos($truncate, ' ');
1686
            if (isset($spacepos)) {
1687
                // ...and cut the text in this position
1688
                $truncate = mb_substr($truncate, 0, $spacepos);
1689
            }
1690
        }
1691
        // add the defined ending to the text
1692
        $truncate .= $ending;
1693
        if ($considerHtml) {
1694
            // close all unclosed html-tags
1695
            foreach ($open_tags as $tag) {
1696
                $truncate .= '</' . $tag . '>';
1697
            }
1698
        }
1699
1700
        return $truncate;
1701
    }
1702
}
1703