Utils   F
last analyzed

Complexity

Total Complexity 162

Size/Duplication

Total Lines 1176
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 525
c 1
b 0
f 0
dl 0
loc 1176
rs 2
wmc 162

40 Methods

Rating   Name   Duplication   Size   Complexity  
A getCookieVar() 0 7 3
A openCollapsableBar() 0 15 3
A cpHeader() 0 16 1
A createCategorySelect() 0 26 5
A getAllowedImagesTypes() 0 11 1
A moduleHome() 0 14 3
A html2text() 0 45 1
B getPathStatus() 0 29 6
A IsUserAdmin() 0 3 1
A getImageDir() 0 9 2
B addCategoryOption() 0 26 7
C uploadFile() 0 60 14
A saveCategoryPermissions() 0 20 3
A getCurrentPage() 0 5 1
A substr() 0 19 2
B mkdir() 0 24 7
A displayFlash() 0 24 6
A IsUserModerator() 0 6 2
A closeCollapsableBar() 0 15 2
A getCurrentUrls() 0 21 3
A IsUserAuthor() 0 5 3
A closeTags() 0 29 6
A getUploadDir() 0 18 4
B seoTitle() 0 110 4
A makeURI() 0 17 4
A stringToInt() 0 6 2
A chmod() 0 3 1
A getOrderBy() 0 7 2
B seoGenUrl() 0 29 8
B renderErrors() 0 23 7
A tellafriend() 0 9 2
A setCookieVar() 0 6 2
A formatErrors() 0 8 2
A newFeatureTag() 0 5 1
A getEditors() 0 21 4
A convertCharset() 0 20 5
A truncateTagSafe() 0 18 4
A createCategoryOptions() 0 19 4
B copyr() 0 34 10
C ratingBar() 0 74 14

How to fix   Complexity   

Complex Class

Complex classes like Utils often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Utils, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace XoopsModules\Publisher;
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
use Criteria;
16
use RuntimeException;
17
use Xmf\Module\Helper\Session;
18
use Xoops;
19
use Xoops\Core\Text\Sanitizer;
20
use XoopsBaseConfig;
21
use XoopsEditorHandler;
22
use XoopsLoad;
23
use XoopsLocale;
24
use XoopsModules\Publisher;
25
26
/**
27
 * @copyright       XOOPS Project (http://xoops.org)
28
 * @license         GNU GPL V2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
29
 * @package         Publisher
30
 * @since           1.0
31
 * @author          trabis <[email protected]>
32
 * @author          The SmartFactory <www.smartfactory.ca>
33
 * @author          trabis <[email protected]>
34
 */
35
class Utils
36
{
37
    /**
38
     * Includes scripts in HTML header
39
     */
40
    public static function cpHeader(): void
41
    {
42
        $xoops = Xoops::getInstance();
43
        $helper = Helper::getInstance();
44
        $xoops->header();
45
46
        $css = [];
47
        $css[] = $helper->path('css/publisher.css');
48
        $xoops->theme()->addBaseStylesheetAssets($css);
49
50
        $js = [];
51
        $js[] = $helper->path('js/funcs.js');
52
        $js[] = $helper->path('js/cookies.js');
53
        $js[] = $helper->path('js/ajaxupload.3.9.js');
54
        $js[] = $helper->path('js/publisher.js');
55
        $xoops->theme()->addBaseScriptAssets($js);
56
    }
57
58
    /**
59
     * Default sorting for a given order
60
     *
61
     * @param string $sort
62
     */
63
    public static function getOrderBy($sort): string
64
    {
65
        if (\in_array($sort, ['datesub', 'counter'])) {
66
            return 'DESC';
67
        }
68
69
        return 'ASC';
70
    }
71
72
    /**
73
     * @credits Thanks to Mithandir
74
     *
75
     * @param string $str
76
     * @param int    $start
77
     * @param int    $length
78
     * @param string $trimmarker
79
     */
80
    public static function substr($str, $start, $length, $trimmarker = '...'): string
81
    {
82
        // if the string is empty, let's get out ;-)
83
        if ('' == $str) {
84
            return $str;
85
        }
86
87
        // reverse a string that is shortened with '' as trimmarker
88
        $reversed_string = \strrev(XoopsLocale::substr($str, $start, $length, ''));
89
90
        // find first space in reversed string
91
        $position_of_space = \mb_strpos($reversed_string, ' ', 0);
92
93
        // truncate the original string to a length of $length
94
        // minus the position of the last space
95
        // plus the length of the $trimmarker
96
        $truncated_string = XoopsLocale::substr($str, $start, $length - $position_of_space + \mb_strlen($trimmarker), $trimmarker);
97
98
        return $truncated_string;
99
    }
100
101
    /**
102
     * @param string $document
103
     */
104
    public static function html2text($document): string
105
    {
106
        // PHP Manual:: function preg_replace
107
        // $document should contain an HTML document.
108
        // This will remove HTML tags, javascript sections
109
        // and white space. It will also convert some
110
        // common HTML entities to their text equivalent.
111
        // Credits : newbb2
112
        $search = [
113
            "'<script[^>]*?>.*?</script>'si", // Strip out javascript
114
            "'<img.*?>'si", // Strip out img tags
115
            "'<[\/\!]*?[^<>]*?>'si", // Strip out HTML tags
116
            "'([\r\n])[\s]+'", // Strip out white space
117
            "'&(quot|#34);'i", // Replace HTML entities
118
            "'&(amp|#38);'i",
119
            "'&(lt|#60);'i",
120
            "'&(gt|#62);'i",
121
            "'&(nbsp|#160);'i",
122
            "'&(iexcl|#161);'i",
123
            "'&(cent|#162);'i",
124
            "'&(pound|#163);'i",
125
            "'&(copy|#169);'i",
126
            "'&#(\d+);'e",
127
        ]; // evaluate as php
128
129
        $replace = [
130
            '',
131
            '',
132
            '',
133
            '\\1',
134
            '"',
135
            '&',
136
            '<',
137
            '>',
138
            ' ',
139
            \chr(161),
140
            \chr(162),
141
            \chr(163),
142
            \chr(169),
143
            'chr(\\1)',
144
        ];
145
146
        $text = \preg_replace($search, $replace, $document);
147
148
        return $text;
149
    }
150
151
    /**
152
     * @return string[]
153
     */
154
    public static function getAllowedImagesTypes(): array
155
    {
156
        return [
157
            'jpg/jpeg',
158
            'image/bmp',
159
            'image/gif',
160
            'image/jpeg',
161
            'image/jpg',
162
            'image/x-png',
163
            'image/png',
164
            'image/pjpeg',
165
        ];
166
    }
167
168
    /**
169
     * @param bool $withLink
170
     *
171
     * @return string
172
     */
173
    public static function moduleHome($withLink = true): ?string
174
    {
175
        $xoops = Xoops::getInstance();
176
        $helper = Helper::getInstance();
177
178
        if (!$helper->getConfig('format_breadcrumb_modname')) {
179
            return '';
180
        }
181
182
        if (!$withLink) {
183
            return $helper->getModule()->getVar('name');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $helper->getModule()->getVar('name') could return the type string[] which is incompatible with the type-hinted return null|string. Consider adding an additional type-check to rule them out.
Loading history...
184
        }
185
186
        return '<a href="' . $xoops->url(\PUBLISHER_URL) . '/">' . $helper->getModule()->getVar('name') . '</a>';
187
    }
188
189
    /**
190
     * Copy a file, or a folder and its contents
191
     *
192
     * @param string $source The source
193
     * @param string $dest   The destination
194
     *
195
     * @return bool Returns true on success, false on failure
196
     * @version     1.0.0
197
     *
198
     * @author      Aidan Lister <[email protected]>
199
     */
200
    public static function copyr($source, $dest): bool
201
    {
202
        // Simple copy for a file
203
        if (\is_file($source)) {
204
            return \copy($source, $dest);
205
        }
206
207
        // Make destination directory
208
        if (!\is_dir($dest)) {
209
            if (!\mkdir($dest) && !\is_dir($dest)) {
210
                throw new RuntimeException(\sprintf('Directory "%s" was not created', $dest));
211
            }
212
        }
213
214
        // Loop through the folder
215
        $dir = \dir($source);
216
        while (false !== $entry = $dir->read()) {
217
            // Skip pointers
218
            if ('.' === $entry || '..' === $entry) {
219
                continue;
220
            }
221
222
            // Deep copy directories
223
            if (\is_dir("$source/$entry") && ($dest !== "$source/$entry")) {
224
                self::copyr("$source/$entry", "$dest/$entry");
225
            } else {
226
                \copy("$source/$entry", "$dest/$entry");
227
            }
228
        }
229
230
        // Clean up
231
        $dir->close();
232
233
        return true;
234
    }
235
236
    /**
237
     * @credits Thanks to the NewBB2 Development Team
238
     * @param string $item
239
     * @param bool   $getStatus
240
     *
241
     * @return bool|int|string
242
     * @todo    check undefined string
243
     */
244
    public static function getPathStatus($item, $getStatus = false)
245
    {
246
        $helper = Helper::getInstance();
247
        if ('root' === $item) {
248
            $path = '';
249
        } else {
250
            $path = $item;
251
        }
252
253
        $thePath = self::getUploadDir(true, $path);
254
255
        if (empty($thePath)) {
256
            return false;
257
        }
258
        if (@\is_writable($thePath)) {
259
            $pathCheckResult = 1;
260
            $path_status = _AM_PUBLISHER_AVAILABLE;
261
        } elseif (!@\is_dir($thePath)) {
262
            $pathCheckResult = -1;
263
            $path_status = _AM_PUBLISHER_NOTAVAILABLE . " <a href='" . $helper->url("admin/index.php?op=createdir&amp;path={$item}") . "'>" . _AM_PUBLISHER_CREATETHEDIR . '</a>';
264
        } else {
265
            $pathCheckResult = -2;
266
            $path_status = \_AM_PUBLISHER_NOTWRITABLE . " <a href='" . $helper->url("admin/index.php?op=setperm&amp;path={$item}") . "'>" . _AM_SCS_SETMPERM . '</a>';
0 ignored issues
show
Bug introduced by
The constant XoopsModules\Publisher\_AM_SCS_SETMPERM was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
267
        }
268
        if (!$getStatus) {
269
            return $path_status;
270
        }
271
272
        return $pathCheckResult;
273
    }
274
275
    /**
276
     * @credits Thanks to the NewBB2 Development Team
277
     *
278
     * @param string $target
279
     */
280
    public static function mkdir($target): bool
281
    {
282
        // http://www.php.net/manual/en/function.mkdir.php
283
        // saint at corenova.com
284
        // bart at cdasites dot com
285
        if (\is_dir($target) || empty($target)) {
286
            return true; // best case check first
287
        }
288
289
        if (XoopsLoad::fileExists($target) && !\is_dir($target)) {
290
            return false;
291
        }
292
293
        if (self::mkdir(\mb_substr($target, 0, \mb_strrpos($target, '/')))) {
294
            if (!XoopsLoad::fileExists($target)) {
295
                $res = \mkdir($target, 0777); // crawl back up & create dir tree
296
                self::chmod($target);
297
298
                return $res;
299
            }
300
        }
301
        $res = \is_dir($target);
302
303
        return $res;
304
    }
305
306
    /**
307
     * @credits Thanks to the NewBB2 Development Team
308
     *
309
     * @param string $target
310
     * @param int    $mode
311
     */
312
    public static function chmod($target, $mode = 0777): bool
313
    {
314
        return @\chmod($target, $mode);
315
    }
316
317
    /**
318
     * @param bool $hasPath
319
     * @param bool|string $item
320
     *
321
     * @return string
322
     */
323
    public static function getUploadDir($hasPath = true, $item = false): ?string
324
    {
325
        $xoops = Xoops::getInstance();
326
        if ($item) {
327
            if ('root' === $item) {
328
                $item = '';
329
            } else {
330
                $item = $item . '/';
0 ignored issues
show
Bug introduced by
Are you sure $item of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

330
                $item = /** @scrutinizer ignore-type */ $item . '/';
Loading history...
331
            }
332
        } else {
333
            $item = '';
334
        }
335
336
        if ($hasPath) {
337
            return $xoops->path(\PUBLISHER_UPLOADS_PATH . '/' . $item);
338
        }
339
340
        return $xoops->url(\PUBLISHER_UPLOADS_URL . '/' . $item);
341
    }
342
343
    /**
344
     * @param string $item
345
     * @param bool   $hasPath
346
     */
347
    public static function getImageDir($item = '', $hasPath = true): string
348
    {
349
        if ($item) {
350
            $item = "images/{$item}";
351
        } else {
352
            $item = 'images';
353
        }
354
355
        return self::getUploadDir($hasPath, $item);
356
    }
357
358
    /**
359
     * @param array $errors
360
     */
361
    public static function formatErrors($errors = []): string
362
    {
363
        $ret = '';
364
        foreach ($errors as $value) {
365
            $ret .= '<br> - ' . $value;
366
        }
367
368
        return $ret;
369
    }
370
371
    /**
372
     * Check is current user is author of a given article
373
     *
374
     * @param object $itemObj
375
     */
376
    public static function IsUserAuthor($itemObj): bool
377
    {
378
        $xoops = Xoops::getInstance();
379
380
        return ($xoops->isUser() && \is_object($itemObj) && ($xoops->user->getVar('uid') == $itemObj->getVar('uid')));
381
    }
382
383
    /**
384
     * Check is current user is moderator of a given article
385
     *
386
     * @param Publisher\Item $itemObj
387
     */
388
    public static function IsUserModerator($itemObj): bool
389
    {
390
        $helper = Helper::getInstance();
391
        $categoriesGranted = $helper->getPermissionHandler()->getGrantedItems('category_moderation');
392
393
        return (\is_object($itemObj) && \in_array($itemObj->getVar('categoryid'), $categoriesGranted));
394
    }
395
396
    public static function IsUserAdmin(): bool
397
    {
398
        return Helper::getInstance()->isUserAdmin();
399
    }
400
401
    /**
402
     * Saves permissions for the selected category
403
     *
404
     * @param array   $groups     : group with granted permission
405
     * @param int $categoryid : categoryid on which we are setting permissions
406
     * @param string  $perm_name  : name of the permission
407
     *
408
     * @return bool : TRUE if the no errors occured
409
     * @todo Move to category class
410
     */
411
    public static function saveCategoryPermissions($groups, $categoryid, $perm_name): bool
412
    {
413
        $xoops = Xoops::getInstance();
414
        $helper = Helper::getInstance();
415
416
        $result = true;
417
418
        $module_id = $helper->getModule()->getVar('mid');
419
        $gpermHandler = $xoops->getHandlerGroupPermission();
420
        // First, if the permissions are already there, delete them
421
        $gpermHandler->deleteByModule($module_id, $perm_name, $categoryid);
422
423
        // Save the new permissions
424
        if (\count($groups) > 0) {
425
            foreach ($groups as $group_id) {
426
                $gpermHandler->addRight($perm_name, $categoryid, $group_id, $module_id);
427
            }
428
        }
429
430
        return $result;
431
    }
432
433
    /**
434
     * @param string $tablename
435
     * @param string $iconname
436
     * @param string $tabletitle
437
     * @param string $tabledsc
438
     * @param bool   $open
439
     */
440
    public static function openCollapsableBar($tablename = '', $iconname = '', $tabletitle = '', $tabledsc = '', $open = true): void
441
    {
442
        $helper = Helper::getInstance();
443
        $image = 'open12.gif';
444
        $display = 'none';
445
        if ($open) {
446
            $image = 'close12.gif';
447
            $display = 'block';
448
        }
449
450
        echo "<h3 style=\"color: #2F5376; font-weight: bold; font-size: 14px; margin: 6px 0 0 0; \"><a href='javascript:;' onclick=\"toggle('" . $tablename . "'); toggleIcon('" . $iconname . "')\";>";
451
        echo "<img id='" . $iconname . "' src='" . $helper->url('images/links/' . $image) . "' alt=''></a>&nbsp;" . $tabletitle . '</h3>';
452
        echo "<div id='" . $tablename . "' style='display: " . $display . ";'>";
453
        if ('' != $tabledsc) {
454
            echo '<span style="color: #567; margin: 3px 0 12px 0; font-size: small; display: block; ">' . $tabledsc . '</span>';
455
        }
456
    }
457
458
    /**
459
     * @param string $name
460
     * @param string $icon
461
     */
462
    public static function closeCollapsableBar($name, $icon): void
463
    {
464
        echo '</div>';
465
466
        $urls = self::getCurrentUrls();
467
        $path = $urls['phpself'];
468
469
        $cookie_name = $path . '_publisher_collaps_' . $name;
470
        $cookie_name = \str_replace('.', '_', $cookie_name);
471
        $cookie = self::getCookieVar($cookie_name, '');
472
473
        if ('none' === $cookie) {
474
            echo '
475
        <script type="text/javascript"><!--
476
        toggle("' . $name . '"); toggleIcon("' . $icon . '");
477
        //-->
478
        </script>
479
        ';
480
        }
481
    }
482
483
    /**
484
     * @param string $name
485
     * @param string $value
486
     * @param int    $time
487
     */
488
    public static function setCookieVar($name, $value, $time = 0): void
489
    {
490
        if (0 == $time) {
491
            $time = \time() + 3600 * 24 * 365;
492
        }
493
        \setcookie($name, $value, $time, '/');
494
    }
495
496
    /**
497
     * @param string $name
498
     * @param string $default
499
     *
500
     * @return string
501
     */
502
    public static function getCookieVar($name, $default = ''): ?string
503
    {
504
        if (isset($_COOKIE[$name]) && ($_COOKIE[$name] > '')) {
505
            return $_COOKIE[$name];
506
        }
507
508
        return $default;
509
    }
510
511
    public static function getCurrentUrls(): array
512
    {
513
        $http = false === \mb_strpos(XoopsBaseConfig::get('url'), 'https://') ? 'http://' : 'https://';
0 ignored issues
show
Bug introduced by
It seems like XoopsBaseConfig::get('url') can also be of type null; however, parameter $haystack of mb_strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

513
        $http = false === \mb_strpos(/** @scrutinizer ignore-type */ XoopsBaseConfig::get('url'), 'https://') ? 'http://' : 'https://';
Loading history...
514
        $phpself = $_SERVER['PHP_SELF'];
515
        $httphost = $_SERVER['HTTP_HOST'];
516
        $querystring = $_SERVER['QUERY_STRING'] ?? '';
517
518
        if ('' != $querystring) {
519
            $querystring = '?' . $querystring;
520
        }
521
522
        $currenturl = $http . $httphost . $phpself . $querystring;
523
524
        $urls = [];
525
        $urls['http'] = $http;
526
        $urls['httphost'] = $httphost;
527
        $urls['phpself'] = $phpself;
528
        $urls['querystring'] = $querystring;
529
        $urls['full'] = $currenturl;
530
531
        return $urls;
532
    }
533
534
    public static function getCurrentPage(): string
535
    {
536
        $urls = self::getCurrentUrls();
537
538
        return $urls['full'];
539
    }
540
541
    /**
542
     * @param object    $categoryObj
543
     * @param int|array $selectedid
544
     * @param int       $level
545
     * @param string    $ret
546
     *
547
     * @todo move to ccategory class
548
     */
549
    public static function addCategoryOption($categoryObj, $selectedid = 0, $level = 0, $ret = ''): string
550
    {
551
        $helper = Helper::getInstance();
552
553
        $spaces = '';
554
        for ($j = 0; $j < $level; ++$j) {
555
            $spaces .= '--';
556
        }
557
558
        $ret .= "<option value='" . $categoryObj->getVar('categoryid') . "'";
559
        if (\is_array($selectedid) && \in_array($categoryObj->getVar('categoryid'), $selectedid)) {
560
            $ret .= " selected='selected'";
561
        } elseif ($categoryObj->getVar('categoryid') == $selectedid) {
562
            $ret .= " selected='selected'";
563
        }
564
        $ret .= '>' . $spaces . $categoryObj->getVar('name') . "</option>\n";
565
566
        $subCategoriesObj = $helper->getCategoryHandler()->getCategories(0, 0, $categoryObj->getVar('categoryid'));
567
        if (\count($subCategoriesObj) > 0) {
568
            ++$level;
569
            foreach ($subCategoriesObj as $subCategoryObj) {
570
                $ret .= self::addCategoryOption($subCategoryObj, $selectedid, $level);
571
            }
572
        }
573
574
        return $ret;
575
    }
576
577
    /**
578
     * @param int    $selectedid
579
     * @param int    $parentcategory
580
     * @param bool   $allCatOption
581
     * @param string $selectname
582
     *
583
     * @todo move to category class
584
     */
585
    public static function createCategorySelect($selectedid = 0, $parentcategory = 0, $allCatOption = true, $selectname = 'options[0]'): string
586
    {
587
        $helper = Helper::getInstance();
588
589
        $selectedid = \explode(',', $selectedid);
590
591
        $ret = "<select name='" . $selectname . "[]' multiple='multiple' size='10'>";
592
        if ($allCatOption) {
593
            $ret .= "<option value='0'";
594
            if (\in_array(0, $selectedid)) {
595
                $ret .= " selected='selected'";
596
            }
597
            $ret .= '>' . _MB_PUBLISHER_ALLCAT . '</option>';
598
        }
599
600
        // Creating category objects
601
        $categoriesObj = $helper->getCategoryHandler()->getCategories(0, 0, $parentcategory);
602
603
        if (\count($categoriesObj) > 0) {
604
            foreach ($categoriesObj as $catID => $categoryObj) {
605
                $ret .= self::addCategoryOption($categoryObj, $selectedid);
606
            }
607
        }
608
        $ret .= '</select>';
609
610
        return $ret;
611
    }
612
613
    /**
614
     * @param int  $selectedid
615
     * @param int  $parentcategory
616
     * @param bool $allCatOption
617
     *
618
     * @todo move to category class
619
     */
620
    public static function createCategoryOptions($selectedid = 0, $parentcategory = 0, $allCatOption = true): string
621
    {
622
        $helper = Helper::getInstance();
623
624
        $ret = '';
625
        if ($allCatOption) {
626
            $ret .= "<option value='0'";
627
            $ret .= '>' . _MB_PUBLISHER_ALLCAT . "</option>\n";
628
        }
629
630
        // Creating category objects
631
        $categoriesObj = $helper->getCategoryHandler()->getCategories(0, 0, $parentcategory);
632
        if (\count($categoriesObj) > 0) {
633
            foreach ($categoriesObj as $categoryObj) {
634
                $ret .= self::addCategoryOption($categoryObj, $selectedid);
635
            }
636
        }
637
638
        return $ret;
639
    }
640
641
    /**
642
     * @param array  $err_arr
643
     * @param string $reseturl
644
     *
645
     * @todo check this undefined strings
646
     */
647
    public static function renderErrors(&$err_arr, $reseturl = ''): void
648
    {
649
        if (\is_array($err_arr) && \count($err_arr) > 0) {
650
            echo '<div id="readOnly" class="errorMsg" style="border:1px solid #D24D00; background:#FEFECC url(' . \PUBLISHER_URL . '/images/important-32.png) no-repeat 7px 50%;color:#333;padding-left:45px;">';
651
652
            echo '<h4 style="text-align:left;margin:0; padding-top:0">' . _AM_PUBLISHER_MSG_SUBMISSION_ERR;
0 ignored issues
show
Bug introduced by
The constant XoopsModules\Publisher\_...SHER_MSG_SUBMISSION_ERR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
653
654
            if ($reseturl) {
655
                echo ' <a href="' . $reseturl . '">[' . _AM_PUBLISHER_TEXT_SESSION_RESET . ']</a>';
0 ignored issues
show
Bug introduced by
The constant XoopsModules\Publisher\_...SHER_TEXT_SESSION_RESET was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
656
            }
657
658
            echo '</h4><ul>';
659
660
            foreach ($err_arr as $key => $error) {
661
                if (\is_array($error)) {
662
                    foreach ($error as $err) {
663
                        echo '<li><a href="#' . $key . '" onclick="var e = xoopsGetElementById(\'' . $key . '\'); e.focus();">' . \htmlspecialchars($err) . '</a></li>';
664
                    }
665
                } else {
666
                    echo '<li><a href="#' . $key . '" onclick="var e = xoopsGetElementById(\'' . $key . '\'); e.focus();">' . \htmlspecialchars($error) . '</a></li>';
667
                }
668
            }
669
            echo '</ul></div><br>';
670
        }
671
    }
672
673
    /**
674
     * Generate publisher URL
675
     *
676
     * @param string $page
677
     * @param array  $vars
678
     * @param bool   $encodeAmp
679
     *
680
     * @credit : xHelp module, developped by 3Dev
681
     */
682
    public static function makeURI($page, $vars = [], $encodeAmp = true): string
683
    {
684
        $joinStr = '';
685
686
        $amp = ($encodeAmp ? '&amp;' : '&');
687
688
        if (!\count($vars)) {
689
            return $page;
690
        }
691
692
        $qs = '';
693
        foreach ($vars as $key => $value) {
694
            $qs .= $joinStr . $key . '=' . $value;
695
            $joinStr = $amp;
696
        }
697
698
        return $page . '?' . $qs;
699
    }
700
701
    /**
702
     * @param string $subject
703
     */
704
    public static function tellafriend($subject = ''): string
705
    {
706
        $xoops = Xoops::getInstance();
707
        if (false !== \mb_strpos($subject, '%')) {
708
            $subject = \rawurldecode($subject);
709
        }
710
        $target_uri = $xoops->url($_SERVER['REQUEST_URI']);
711
712
        return $xoops->url('modules/tellafriend/index.php?target_uri=' . \rawurlencode($target_uri) . '&amp;subject=' . \rawurlencode($subject));
713
    }
714
715
    /**
716
     * @param bool $another
717
     * @param bool $withRedirect
718
     * @param      $itemObj
719
     *
720
     * @return bool|string
721
     */
722
    public static function uploadFile($another, $withRedirect, &$itemObj)
723
    {
724
        $xoops = Xoops::getInstance();
725
726
        $helper = Helper::getInstance();
727
728
        $itemid = isset($_POST['itemid']) ? (int)$_POST['itemid'] : 0;
729
        $uid = $xoops->isUser() ? $xoops->user->getVar('uid') : 0;
730
        $session = new Session();
731
        $session->set('publisher_file_filename', $_POST['item_file_name'] ?? '');
732
        $session->set('publisher_file_description', $_POST['item_file_description'] ?? '');
733
        $session->set('publisher_file_status', isset($_POST['item_file_status']) ? (int)$_POST['item_file_status'] : 1);
734
        $session->set('publisher_file_uid', $uid);
735
        $session->set('publisher_file_itemid', $itemid);
736
737
        if (!\is_object($itemObj)) {
738
            $itemObj = $helper->getItemHandler()->get($itemid);
739
        }
740
741
        $fileObj = $helper->getFileHandler()->create();
742
        $fileObj->setVar('name', $_POST['item_file_name'] ?? '');
743
        $fileObj->setVar('description', $_POST['item_file_description'] ?? '');
744
        $fileObj->setVar('status', isset($_POST['item_file_status']) ? (int)$_POST['item_file_status'] : 1);
745
        $fileObj->setVar('uid', $uid);
746
        $fileObj->setVar('itemid', $itemObj->getVar('itemid'));
747
        $fileObj->setVar('datesub', \time());
748
749
        // Get available mimetypes for file uploading
750
        $allowed_mimetypes = $helper->getMimetypeHandler()->getArrayByType();
0 ignored issues
show
Bug introduced by
The method getArrayByType() does not exist on XoopsModules\Publisher\MimetypeHandler. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

750
        $allowed_mimetypes = $helper->getMimetypeHandler()->/** @scrutinizer ignore-call */ getArrayByType();
Loading history...
751
        // TODO : display the available mimetypes to the user
752
        $errors = [];
753
        /* @var Publisher\File $fileObj */
754
        if ($helper->getConfig('perm_upload') && \is_uploaded_file($_FILES['item_upload_file']['tmp_name'])) {
755
            if (!$ret = $fileObj->checkUpload('item_upload_file', $allowed_mimetypes, $errors)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $ret is dead and can be removed.
Loading history...
756
                $errorstxt = \implode('<br>', $errors);
757
758
                $message = \sprintf(_CO_PUBLISHER_MESSAGE_FILE_ERROR, $errorstxt);
759
                if ($withRedirect) {
760
                    $xoops->redirect('file.php?op=mod&itemid=' . $itemid, 5, $message);
761
                } else {
762
                    return $message;
763
                }
764
            }
765
        }
766
767
        // Storing the file
768
        if (!$fileObj->store($allowed_mimetypes)) {
769
            if ($withRedirect) {
770
                $xoops->redirect('file.php?op=mod&itemid=' . $fileObj->getVar('itemid'), 3, _CO_PUBLISHER_FILEUPLOAD_ERROR . self::formatErrors($fileObj->getErrors()));
771
            } else {
772
                return _CO_PUBLISHER_FILEUPLOAD_ERROR . self::formatErrors($fileObj->getErrors());
773
            }
774
        }
775
776
        if ($withRedirect) {
777
            $redirect_page = $another ? 'file.php' : 'item.php';
778
            $xoops->redirect($redirect_page . '?op=mod&itemid=' . $fileObj->getVar('itemid'), 2, _CO_PUBLISHER_FILEUPLOAD_SUCCESS);
779
        }
780
781
        return true;
782
    }
783
784
    public static function newFeatureTag(): string
785
    {
786
        $ret = '<span style="padding-right: 4px; font-weight: bold; color: #ff0000;">' . _CO_PUBLISHER_NEW_FEATURE . '</span>';
787
788
        return $ret;
789
    }
790
791
    /**
792
     * Smarty truncate_tagsafe modifier plugin
793
     * Type:     modifier<br>
794
     * Name:     truncate_tagsafe<br>
795
     * Purpose:  Truncate a string to a certain length if necessary,
796
     *           optionally splitting in the middle of a word, and
797
     *           appending the $etc string or inserting $etc into the middle.
798
     *           Makes sure no tags are left half-open or half-closed
799
     *           (e.g. "Banana in a <a...")
800
     *
801
     * @param string
802
     * @param int
803
     * @param string
804
     * @param bool
805
     * @param bool
806
     * @param mixed $string
807
     * @param mixed $length
808
     * @param mixed $etc
809
     * @param mixed $break_words
810
     *
811
     * @return string
812
     * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
813
     *           <amos dot robinson at gmail dot com>
814
     */
815
    public static function truncateTagSafe($string, $length = 80, $etc = '...', $break_words = false): ?string
816
    {
817
        if (0 == $length) {
818
            return '';
819
        }
820
821
        if (\mb_strlen($string) > $length) {
822
            $length -= \mb_strlen($etc);
823
            if (!$break_words) {
824
                $string = \preg_replace('/\s+?(\S+)?$/', '', \mb_substr($string, 0, $length + 1));
825
                $string = \preg_replace('/<[^>]*$/', '', $string);
826
                $string = self::closeTags($string);
827
            }
828
829
            return $string . $etc;
830
        }
831
832
        return $string;
833
    }
834
835
    /**
836
     * @param string $string
837
     *
838
     * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
839
     *           <amos dot robinson at gmail dot com>
840
     */
841
    public static function closeTags($string): string
842
    {
843
        // match opened tags
844
        if (\preg_match_all('/<([a-z\:\-]+)[^\/]>/', $string, $start_tags)) {
845
            $start_tags = $start_tags[1];
846
            // match closed tags
847
            if (\preg_match_all('/<\/([a-z]+)>/', $string, $end_tags)) {
848
                $complete_tags = [];
849
                $end_tags = $end_tags[1];
850
851
                foreach ($start_tags as $val) {
852
                    $posb = \array_search($val, $end_tags);
853
                    if (\is_int($posb)) {
854
                        unset($end_tags[$posb]);
855
                    } else {
856
                        $complete_tags[] = $val;
857
                    }
858
                }
859
            } else {
860
                $complete_tags = $start_tags;
861
            }
862
863
            $complete_tags = \array_reverse($complete_tags);
864
            foreach ($complete_tags as $iValue) {
865
                $string .= '</' . $iValue . '>';
866
            }
867
        }
868
869
        return $string;
870
    }
871
872
    /**
873
     * @param int $itemid
874
     *
875
     * @return string
876
     */
877
    public static function ratingBar($itemid): ?string
878
    {
879
        $xoops = Xoops::getInstance();
880
        $helper = Helper::getInstance();
881
        $rating_unitwidth = 30;
882
        $units = 5;
883
884
        $criteria = new Criteria('itemid', $itemid);
885
        $ratingObjs = $helper->getRatingHandler()->getObjects($criteria);
886
        unset($criteria);
887
888
        $uid = $xoops->isUser() ? $xoops->user->getVar('uid') : 0;
889
        $count = \count($ratingObjs);
890
        $current_rating = 0;
891
        $voted = false;
892
        $ip = \getenv('REMOTE_ADDR');
893
894
        /* @var Publisher\Rating $ratingObj */
895
        foreach ($ratingObjs as $ratingObj) {
896
            $current_rating += $ratingObj->getVar('rate');
897
            if ($ratingObj->getVar('ip') == $ip || ($uid > 0 && $uid == $ratingObj->getVar('uid'))) {
898
                $voted = true;
899
            }
900
        }
901
902
        $tense = 1 == $count ? _MD_PUBLISHER_VOTE_lVOTE : _MD_PUBLISHER_VOTE_lVOTES; //plural form votes/vote
903
904
        // now draw the rating bar
905
        $rating_width = @\number_format($count==0 ? 0 : ($current_rating / $count), 2) * $rating_unitwidth;
906
        $rating1 = @\number_format($count==0 ? 0 : ($current_rating / $count), 1);
907
        $rating2 = @\number_format($count==0 ? 0 : ($current_rating / $count), 2);
908
909
        $groups = $xoops->getUserGroups();
910
        $gpermHandler = $helper->getGrouppermHandler();
911
912
        if (!$gpermHandler->checkRight('global', \_PUBLISHER_RATE, $groups, $helper->getModule()->getVar('mid'))) {
913
            $static_rater = [];
914
            $static_rater[] .= "\n" . '<div class="publisher_ratingblock">';
915
            $static_rater[] .= '<div id="unit_long' . $itemid . '">';
916
            $static_rater[] .= '<div id="unit_ul' . $itemid . '" class="publisher_unit-rating" style="width:' . $rating_unitwidth * $units . 'px;">';
917
            $static_rater[] .= '<div class="publisher_current-rating" style="width:' . $rating_width . 'px;">' . _MD_PUBLISHER_VOTE_RATING . ' ' . $rating2 . '/' . $units . '</div>';
918
            $static_rater[] .= '</div>';
919
            $static_rater[] .= '<div class="publisher_static">' . _MD_PUBLISHER_VOTE_RATING . ': <strong> ' . $rating1 . '</strong>/' . $units . ' (' . $count . ' ' . $tense . ') <br><em>' . _MD_PUBLISHER_VOTE_DISABLE . '</em></div>';
920
            $static_rater[] .= '</div>';
921
            $static_rater[] .= '</div>' . "\n\n";
922
923
            return \implode("\n", $static_rater);
924
        }
925
926
        $rater = '';
927
        $rater .= '<div class="publisher_ratingblock">';
928
        $rater .= '<div id="unit_long' . $itemid . '">';
929
        $rater .= '<div id="unit_ul' . $itemid . '" class="publisher_unit-rating" style="width:' . $rating_unitwidth * $units . 'px;">';
930
        $rater .= '<div class="publisher_current-rating" style="width:' . $rating_width . 'px;">' . _MD_PUBLISHER_VOTE_RATING . ' ' . $rating2 . '/' . $units . '</div>';
931
932
        for ($ncount = 1; $ncount <= $units; ++$ncount) { // loop from 1 to the number of units
933
            if (!$voted) { // if the user hasn't yet voted, draw the voting stars
934
                $rater .= '<div><a href="' . \PUBLISHER_URL . '/rate.php?itemid=' . $itemid . '&amp;rating=' . $ncount . '" title="' . $ncount . ' ' . _MD_PUBLISHER_VOTE_OUTOF . ' ' . $units . '" class="publisher_r' . $ncount . '-unit rater" rel="nofollow">' . $ncount . '</a></div>';
935
            }
936
        }
937
938
        $rater .= '  </div>';
939
        $rater .= '  <div';
940
941
        if ($voted) {
942
            $rater .= ' class="publisher_voted"';
943
        }
944
945
        $rater .= '>' . _MD_PUBLISHER_VOTE_RATING . ': <strong> ' . $rating1 . '</strong>/' . $units . ' (' . $count . ' ' . $tense . ')';
946
        $rater .= '  </div>';
947
        $rater .= '</div>';
948
        $rater .= '</div>';
949
950
        return $rater;
951
    }
952
953
    /**
954
     * @param array $allowed_editors
955
     */
956
    public static function getEditors($allowed_editors = null): array
957
    {
958
        $ret = [];
959
        $nohtml = false;
960
        $editorHandler = XoopsEditorHandler::getInstance();
961
        $editors = $editorHandler->getList($nohtml);
962
        foreach ($editors as $name => $title) {
963
            $key = self::stringToInt($name);
964
            if (\is_array($allowed_editors)) {
965
                //for submit page
966
                if (\in_array($key, $allowed_editors)) {
967
                    $ret[] = $name;
968
                }
969
            } else {
970
                //for admin permissions page
971
                $ret[$key]['name'] = $name;
972
                $ret[$key]['title'] = $title;
973
            }
974
        }
975
976
        return $ret;
977
    }
978
979
    /**
980
     * @param string $string
981
     * @param int    $length
982
     */
983
    public static function stringToInt($string = '', $length = 5): int
984
    {
985
        for ($i = 0, $final = '', $string = \mb_substr(\md5($string), $length); $i < $length; $final .= (int)$string[$i], ++$i) {
986
        }
987
988
        return (int)$final;
989
    }
990
991
    /**
992
     * @param string $item
993
     *
994
     * @return string
995
     */
996
    public static function convertCharset($item): ?string
997
    {
998
        if ('UTF-8' === XoopsLocale::getCharset()) {
999
            return $item;
1000
        }
1001
1002
        if ('windows-1256' !== XoopsLocale::getCharset()) {
1003
            return utf8_encode($item);
1004
        }
1005
1006
        if ($unserialize = \unserialize($item)) {
1007
            foreach ($unserialize as $key => $value) {
1008
                $unserialize[$key] = @iconv('windows-1256', 'UTF-8', $value);
1009
            }
1010
            $serialize = \serialize($unserialize);
1011
1012
            return $serialize;
1013
        }
1014
1015
        return @iconv('windows-1256', 'UTF-8', $item);
0 ignored issues
show
Bug Best Practice introduced by
The expression return @iconv('windows-1256', 'UTF-8', $item) could return the type false which is incompatible with the type-hinted return null|string. Consider adding an additional type-check to rule them out.
Loading history...
1016
    }
1017
1018
    /**
1019
     * @param string $title
1020
     * @param bool   $withExt
1021
     * @return string|string[]|null
1022
     */
1023
1024
    /**
1025
     * @param string $title
1026
     * @param bool   $withExt
1027
     * @return string|string[]|null
1028
     */
1029
    public static function seoTitle($title = '', $withExt = true)
1030
    {
1031
        /**
1032
         * if XOOPS ML is present, let's sanitize the title with the current language
1033
         */
1034
        $myts = Sanitizer::getInstance();
1035
        if (\method_exists($myts, 'formatForML')) {
1036
            $title = $myts->formatForML($title);
1037
        }
1038
1039
        // Transformation de la chaine en minuscule
1040
        // Codage de la chaine afin d'éviter les erreurs 500 en cas de caractères imprévus
1041
        $title = \rawurlencode(\mb_strtolower($title));
1042
1043
        // Transformation des ponctuations
1044
        //                 Tab     Space      !        "        #        %        &        '        (        )        ,        /        :        ;        <        =        >        ?        @        [        \        ]        ^        {        |        }        ~       .
1045
        $pattern = [
1046
            '/%09/',
1047
            '/%20/',
1048
            '/%21/',
1049
            '/%22/',
1050
            '/%23/',
1051
            '/%25/',
1052
            '/%26/',
1053
            '/%27/',
1054
            '/%28/',
1055
            '/%29/',
1056
            '/%2C/',
1057
            '/%2F/',
1058
            '/%3A/',
1059
            '/%3B/',
1060
            '/%3C/',
1061
            '/%3D/',
1062
            '/%3E/',
1063
            '/%3F/',
1064
            '/%40/',
1065
            '/%5B/',
1066
            '/%5C/',
1067
            '/%5D/',
1068
            '/%5E/',
1069
            '/%7B/',
1070
            '/%7C/',
1071
            '/%7D/',
1072
            '/%7E/',
1073
            "/\./",
1074
        ];
1075
        $rep_pat = [
1076
            '-',
1077
            '-',
1078
            '',
1079
            '',
1080
            '',
1081
            '-100',
1082
            '',
1083
            '-',
1084
            '',
1085
            '',
1086
            '',
1087
            '-',
1088
            '',
1089
            '',
1090
            '',
1091
            '-',
1092
            '',
1093
            '',
1094
            '-at-',
1095
            '',
1096
            '-',
1097
            '',
1098
            '-',
1099
            '',
1100
            '-',
1101
            '',
1102
            '-',
1103
            '',
1104
        ];
1105
        $title = \preg_replace($pattern, $rep_pat, $title);
1106
1107
        // Transformation des caractères accentués
1108
        //                  è        é        ê        ë        ç        à        â        ä        î        ï        ù        ü        û        ô        ö
1109
        $pattern = [
1110
            '/%B0/',
1111
            '/%E8/',
1112
            '/%E9/',
1113
            '/%EA/',
1114
            '/%EB/',
1115
            '/%E7/',
1116
            '/%E0/',
1117
            '/%E2/',
1118
            '/%E4/',
1119
            '/%EE/',
1120
            '/%EF/',
1121
            '/%F9/',
1122
            '/%FC/',
1123
            '/%FB/',
1124
            '/%F4/',
1125
            '/%F6/',
1126
        ];
1127
        $rep_pat = ['-', 'e', 'e', 'e', 'e', 'c', 'a', 'a', 'a', 'i', 'i', 'u', 'u', 'u', 'o', 'o'];
1128
        $title = \preg_replace($pattern, $rep_pat, $title);
1129
1130
        if (\count($title) > 0) {
0 ignored issues
show
Bug introduced by
$title of type string is incompatible with the type Countable|array expected by parameter $value of count(). ( Ignorable by Annotation )

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

1130
        if (\count(/** @scrutinizer ignore-type */ $title) > 0) {
Loading history...
1131
            if ($withExt) {
1132
                $title .= '.html';
1133
            }
1134
1135
            return $title;
1136
        }
1137
1138
        return '';
1139
    }
1140
1141
    /**
1142
     * seoGenUrl
1143
     *
1144
     * @param string  $op
1145
     * @param int $id
1146
     * @param string  $short_url
1147
     *
1148
     * @return string
1149
     */
1150
    public static function seoGenUrl($op, $id, $short_url = ''): ?string
1151
    {
1152
        $helper = Helper::getInstance();
1153
        if ('none' !== $helper->getConfig('seo_url_rewrite')) {
1154
            if (!empty($short_url)) {
1155
                $short_url = $short_url . '.html';
1156
            }
1157
1158
            if ('htaccess' === $helper->getConfig('seo_url_rewrite')) {
1159
                // generate SEO url using htaccess
1160
                return XoopsBaseConfig::get('url') . '/' . $helper->getConfig('seo_module_name') . ".${op}.${id}/${short_url}";
1161
            }
1162
1163
            if ('path-info' === $helper->getConfig('seo_url_rewrite')) {
1164
                // generate SEO url using path-info
1165
                return $helper->url("index.php/${op}.${id}/${short_url}");
1166
            }
1167
1168
            die('Unknown SEO method.');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1169
        }
1170
        // generate classic url
1171
        switch ($op) {
1172
                case 'category':
1173
                    return $helper->url("${op}.php?categoryid=${id}");
1174
                case 'item':
1175
                case 'print':
1176
                    return $helper->url("${op}.php?itemid=${id}");
1177
                default:
1178
                    die('Unknown SEO operation.');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1179
            }
1180
    }
1181
1182
    /**
1183
     * @param string $url
1184
     * @param int    $width
1185
     * @param int    $height
1186
     */
1187
    public static function displayFlash($url, $width = 0, $height = 0): string
1188
    {
1189
        if (!$width || !$height) {
1190
            if (!$dimension = @\getimagesize($url)) {
1191
                return "<a href='{$url}' target='_blank'>{$url}</a>";
1192
            }
1193
            if (!$width) {
1194
                $height = $dimension[1] * $width / $dimension[0];
1195
            } elseif (!empty($height)) {
1196
                $width = $dimension[0] * $height / $dimension[1];
1197
            } else {
1198
                [$width, $height] = [$dimension[0], $dimension[1]];
1199
            }
1200
        }
1201
1202
        $rp = "<object width='{$width}' height='{$height}' classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0'>";
1203
        $rp .= "<param name='movie' value='{$url}'>";
1204
        $rp .= "<param name='QUALITY' value='high'>";
1205
        $rp .= "<PARAM NAME='bgcolor' VALUE='#FFFFFF'>";
1206
        $rp .= "<param name='wmode' value='transparent'>";
1207
        $rp .= "<embed src='{$url}' width='{$width}' height='{$height}' quality='high' bgcolor='#FFFFFF' wmode='transparent'  pluginspage='http://www.macromedia.com/go/getflashplayer' type='application/x-shockwave-flash'></embed>";
1208
        $rp .= '</object>';
1209
1210
        return $rp;
1211
    }
1212
}
1213