Passed
Branch master (410c7b)
by Michael
03:30
created

SysUtility::truncateHtml()   F

Complexity

Conditions 19
Paths 194

Size

Total Lines 129
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 46
dl 0
loc 129
rs 3.7333
c 0
b 0
f 0
cc 19
nc 194
nop 5

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace XoopsModules\Suico\Common;
6
7
/*
8
 Utility Class Definition
9
 You may not change or alter any portion of this comment or credits of
10
 supporting developers from this source code or any supporting source code
11
 which is considered copyrighted (c) material of the original comment or credit
12
 authors.
13
14
 This program is distributed in the hope that it will be useful, but
15
 WITHOUT ANY WARRANTY; without even the implied warranty of
16
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
 */
18
19
/**
20
 * @license      https://www.fsf.org/copyleft/gpl.html GNU public license
21
 * @copyright    https://xoops.org 2000-2020 &copy; XOOPS Project
22
 * @author       ZySpec <[email protected]>
23
 * @author       Mamba <[email protected]>
24
 */
25
26
use Xmf\Request;
27
use XoopsFormDhtmlTextArea;
28
use XoopsFormEditor;
29
use XoopsModules\Suico;
30
use XoopsModules\Suico\Helper;
31
32
/**
33
 * Class SysUtility
34
 */
35
class SysUtility
36
{
37
    use VersionChecks;
0 ignored issues
show
introduced by
The trait XoopsModules\Suico\Common\VersionChecks requires some properties which are not provided by XoopsModules\Suico\Common\SysUtility: $tag_name, $prerelease
Loading history...
38
    use ServerStats;
39
    use FilesManagement;
40
41
    // Files Management Trait
42
43
    //--------------- Custom module methods -----------------------------
44
45
    /**
46
     * @param $text
47
     * @param $form_sort
48
     * @return string
49
     */
50
51
    public static function selectSorting($text, $form_sort)
52
    {
53
        global $start, $order, $file_cat, $sort, $xoopsModule;
54
55
        $select_view = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $select_view is dead and can be removed.
Loading history...
56
57
        $moduleDirName = \basename(\dirname(__DIR__, 2));
0 ignored issues
show
Unused Code introduced by
The assignment to $moduleDirName is dead and can be removed.
Loading history...
58
59
        $helper = Helper::getInstance();
60
61
        //        $pathModIcon16 = XOOPS_URL . '/modules/' . $moduleDirName . '/' . $helper->getModule()->getInfo('modicons16');
62
63
        $pathModIcon16 = $helper->url($helper->getModule()->getInfo('modicons16'));
0 ignored issues
show
Bug introduced by
It seems like $helper->getModule()->getInfo('modicons16') can also be of type array; however, parameter $url of Xmf\Module\Helper\GenericHelper::url() 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

63
        $pathModIcon16 = $helper->url(/** @scrutinizer ignore-type */ $helper->getModule()->getInfo('modicons16'));
Loading history...
64
65
        $select_view = '<form name="form_switch" id="form_switch" action="' . Request::getString('REQUEST_URI', '', 'SERVER') . '" method="post"><span style="font-weight: bold;">' . $text . '</span>';
66
67
        //$sorts =  $sort ==  'asc' ? 'desc' : 'asc';
68
69
        if ($form_sort == $sort) {
70
            $sel1 = 'asc' === $order ? 'selasc.png' : 'asc.png';
71
72
            $sel2 = 'desc' === $order ? 'seldesc.png' : 'desc.png';
73
        } else {
74
            $sel1 = 'asc.png';
75
76
            $sel2 = 'desc.png';
77
        }
78
79
        $select_view .= '  <a href="' . Request::getString('PHP_SELF', '', 'SERVER') . '?start=' . $start . '&sort=' . $form_sort . '&order=asc"><img src="' . $pathModIcon16 . '/' . $sel1 . '" title="ASC" alt="ASC"></a>';
80
81
        $select_view .= '<a href="' . Request::getString('PHP_SELF', '', 'SERVER') . '?start=' . $start . '&sort=' . $form_sort . '&order=desc"><img src="' . $pathModIcon16 . '/' . $sel2 . '" title="DESC" alt="DESC"></a>';
82
83
        $select_view .= '</form>';
84
85
        return $select_view;
86
    }
87
88
    /***************Blocks***************/
89
90
    /**
91
     * @param array $cats
92
     * @return string
93
     */
94
95
    public static function blockAddCatSelect($cats)
96
    {
97
        $cat_sql = '';
98
99
        if (\is_array($cats) && !empty($cats)) {
100
            $cat_sql = '(' . \current($cats);
101
102
            \array_shift($cats);
103
104
            foreach ($cats as $cat) {
105
                $cat_sql .= ',' . $cat;
106
            }
107
108
            $cat_sql .= ')';
109
        }
110
111
        return $cat_sql;
112
    }
113
114
    /**
115
     * @param $content
116
     */
117
118
    public static function metaKeywords($content)
119
    {
120
        global $xoopsTpl, $xoTheme;
121
122
        $myts = \MyTextSanitizer::getInstance();
123
124
        $content = $myts->undoHtmlSpecialChars($myts->displayTarea($content));
125
126
        if (null !== $xoTheme && \is_object($xoTheme)) {
127
            $xoTheme->addMeta('meta', 'keywords', \strip_tags($content));
128
        } else {    // Compatibility for old Xoops versions
129
            $xoopsTpl->assign('xoops_metaKeywords', \strip_tags($content));
130
        }
131
    }
132
133
    /**
134
     * @param $content
135
     */
136
137
    public static function metaDescription($content)
138
    {
139
        global $xoopsTpl, $xoTheme;
140
141
        $myts = \MyTextSanitizer::getInstance();
142
143
        $content = $myts->undoHtmlSpecialChars($myts->displayTarea($content));
144
145
        if (null !== $xoTheme && \is_object($xoTheme)) {
146
            $xoTheme->addMeta('meta', 'description', \strip_tags($content));
147
        } else {    // Compatibility for old Xoops versions
148
            $xoopsTpl->assign('xoops_metaDescription', \strip_tags($content));
149
        }
150
    }
151
152
    /**
153
     * @param $tableName
154
     * @param $columnName
155
     *
156
     * @return array
157
     */
158
159
    public static function enumerate($tableName, $columnName)
160
    {
161
        $table = $GLOBALS['xoopsDB']->prefix($tableName);
162
163
        //    $result = $GLOBALS['xoopsDB']->query("SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
164
165
        //        WHERE TABLE_NAME = '" . $table . "' AND COLUMN_NAME = '" . $columnName . "'")
166
167
        //    || exit ($GLOBALS['xoopsDB']->error());
168
169
        $sql = 'SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = "' . $table . '" AND COLUMN_NAME = "' . $columnName . '"';
170
171
        $result = $GLOBALS['xoopsDB']->query($sql);
172
173
        if (!$result) {
174
            exit($GLOBALS['xoopsDB']->error());
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...
175
        }
176
177
        $row = $GLOBALS['xoopsDB']->fetchBoth($result);
178
179
        $enumList = \explode(',', \str_replace("'", '', \mb_substr($row['COLUMN_TYPE'], 5, -6)));
180
181
        return $enumList;
182
    }
183
184
    /**
185
     * @param array|string $tableName
186
     * @param int          $id_field
187
     * @param int          $id
188
     *
189
     * @return mixed
190
     */
191
192
    public static function cloneRecord($tableName, $id_field, $id)
193
    {
194
        $new_id = false;
195
196
        $table = $GLOBALS['xoopsDB']->prefix($tableName);
197
198
        // copy content of the record you wish to clone
199
200
        $tempTable = $GLOBALS['xoopsDB']->fetchArray($GLOBALS['xoopsDB']->query("SELECT * FROM $table WHERE $id_field='$id' "), \MYSQLI_ASSOC) or exit('Could not select record');
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...
201
202
        // set the auto-incremented id's value to blank.
203
204
        unset($tempTable[$id_field]);
205
206
        // insert cloned copy of the original  record
207
208
        $result = $GLOBALS['xoopsDB']->queryF("INSERT INTO $table (" . \implode(', ', \array_keys($tempTable)) . ") VALUES ('" . \implode("', '", $tempTable) . "')") or exit($GLOBALS['xoopsDB']->error());
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...
209
210
        if ($result) {
211
            // Return the new id
212
213
            $new_id = $GLOBALS['xoopsDB']->getInsertId();
214
        }
215
216
        return $new_id;
217
    }
218
219
    /**
220
     * truncateHtml can truncate a string up to a number of characters while preserving whole words and HTML tags
221
     * www.gsdesign.ro/blog/cut-html-string-without-breaking-the-tags
222
     * www.cakephp.org
223
     *
224
     * @param string $text         String to truncate.
225
     * @param int    $length       Length of returned string, including ellipsis.
226
     * @param string $ending       Ending to be appended to the trimmed string.
227
     * @param bool   $exact        If false, $text will not be cut mid-word
228
     * @param bool   $considerHtml If true, HTML tags would be handled correctly
229
     *
230
     * @return string Trimmed string.
231
     */
232
233
    public static function truncateHtml($text, $length = 100, $ending = '...', $exact = false, $considerHtml = true)
234
    {
235
        $openTags = [];
236
237
        if ($considerHtml) {
238
            // if the plain text is shorter than the maximum length, return the whole text
239
240
            if (\mb_strlen(\preg_replace('/<.*?' . '>/', '', $text)) <= $length) {
241
                return $text;
242
            }
243
244
            // splits all html-tags to scanable lines
245
246
            \preg_match_all('/(<.+?' . '>)?([^<>]*)/s', $text, $lines, \PREG_SET_ORDER);
247
248
            $total_length = mb_strlen($ending);
249
250
            //$openTags    = [];
251
252
            $truncate = '';
253
254
            foreach ($lines as $line_matchings) {
255
                // if there is any html-tag in this line, handle it and add it (uncounted) to the output
256
257
                if (!empty($line_matchings[1])) {
258
                    // if it's an "empty element" with or without xhtml-conform closing slash
259
260
                    if (\preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $line_matchings[1])) {
261
                        // do nothing
262
                        // if tag is a closing tag
263
                    } elseif (\preg_match('/^<\s*\/(\S+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {
264
                        // delete tag from $openTags list
265
266
                        $pos = \array_search($tag_matchings[1], $openTags);
267
268
                        if (false !== $pos) {
269
                            unset($openTags[$pos]);
270
                        }
271
                        // if tag is an opening tag
272
                    } elseif (\preg_match('/^<\s*([^\s>!]+).*?' . '>$/s', $line_matchings[1], $tag_matchings)) {
273
                        // add tag to the beginning of $openTags list
274
275
                        \array_unshift($openTags, \mb_strtolower($tag_matchings[1]));
276
                    }
277
278
                    // add html-tag to $truncate'd text
279
280
                    $truncate .= $line_matchings[1];
281
                }
282
283
                // calculate the length of the plain text part of the line; handle entities as one character
284
285
                $content_length = \mb_strlen(\preg_replace('/&[0-9a-z]{2,8};|&#\d{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
286
287
                if ($total_length + $content_length > $length) {
288
                    // the number of characters which are left
289
290
                    $left = $length - $total_length;
291
292
                    $entities_length = 0;
293
294
                    // search for html entities
295
296
                    if (\preg_match_all('/&[0-9a-z]{2,8};|&#\d{1,7};|[0-9a-f]{1,6};/i', $line_matchings[2], $entities, \PREG_OFFSET_CAPTURE)) {
297
                        // calculate the real length of all entities in the legal range
298
299
                        foreach ($entities[0] as $entity) {
300
                            if ($left >= $entity[1] + 1 - $entities_length) {
301
                                $left--;
302
303
                                $entities_length += \mb_strlen($entity[0]);
304
                            } else {
305
                                // no more characters left
306
307
                                break;
308
                            }
309
                        }
310
                    }
311
312
                    $truncate .= \mb_substr($line_matchings[2], 0, $left + $entities_length);
313
314
                    // maximum lenght is reached, so get off the loop
315
316
                    break;
317
                }
318
319
                $truncate .= $line_matchings[2];
320
321
                $total_length += $content_length;
322
323
                // if the maximum length is reached, get off the loop
324
325
                if ($total_length >= $length) {
326
                    break;
327
                }
328
            }
329
        } elseif (\mb_strlen($text) <= $length) {
330
            return $text;
331
        }
332
333
        $truncate = \mb_substr($text, 0, $length - \mb_strlen($ending));
334
335
        // if the words shouldn't be cut in the middle...
336
337
        if (!$exact) {
338
            // ...search the last occurance of a space...
339
340
            $spacepos = \mb_strrpos($truncate, ' ');
341
342
            if (isset($spacepos)) {
343
                // ...and cut the text in this position
344
345
                $truncate = \mb_substr($truncate, 0, $spacepos);
346
            }
347
        }
348
349
        // add the defined ending to the text
350
351
        $truncate .= $ending;
352
353
        if ($considerHtml) {
354
            // close all unclosed html-tags
355
356
            foreach ($openTags as $tag) {
357
                $truncate .= '</' . $tag . '>';
358
            }
359
        }
360
361
        return $truncate;
362
    }
363
364
    /**
365
     * @param \Xmf\Module\Helper $helper
366
     * @param array|null         $options
367
     * @return \XoopsFormDhtmlTextArea|\XoopsFormEditor
368
     */
369
370
    public static function getEditor(
371
        $helper = null,
372
        $options = null
373
    ) {
374
        /** @var Helper $helper */
375
376
        if (null === $options) {
377
            $options = [];
378
379
            $options['name'] = 'Editor';
380
381
            $options['value'] = 'Editor';
382
383
            $options['rows'] = 10;
384
385
            $options['cols'] = '100%';
386
387
            $options['width'] = '100%';
388
389
            $options['height'] = '400px';
390
        }
391
392
        if (null === $helper) {
393
            $helper = Helper::getInstance();
394
        }
395
396
        $isAdmin = $helper->isUserAdmin();
397
398
        if (\class_exists('XoopsFormEditor')) {
399
            if ($isAdmin) {
400
                $descEditor = new XoopsFormEditor(
401
                    \ucfirst($options['name']), $helper->getConfig(
402
                    'editorAdmin'
403
                ), $options, $nohtml = false, $onfailure = 'textarea'
404
                );
405
            } else {
406
                $descEditor = new XoopsFormEditor(
407
                    \ucfirst($options['name']), $helper->getConfig(
408
                    'editorUser'
409
                ), $options, $nohtml = false, $onfailure = 'textarea'
410
                );
411
            }
412
        } else {
413
            $descEditor = new XoopsFormDhtmlTextArea(
414
                \ucfirst(
415
                    $options['name']
416
                ), $options['name'], $options['value'], '100%', '100%'
0 ignored issues
show
Bug introduced by
'100%' of type string is incompatible with the type integer expected by parameter $rows of XoopsFormDhtmlTextArea::__construct(). ( Ignorable by Annotation )

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

416
                ), $options['name'], $options['value'], /** @scrutinizer ignore-type */ '100%', '100%'
Loading history...
Bug introduced by
'100%' of type string is incompatible with the type integer expected by parameter $cols of XoopsFormDhtmlTextArea::__construct(). ( Ignorable by Annotation )

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

416
                ), $options['name'], $options['value'], '100%', /** @scrutinizer ignore-type */ '100%'
Loading history...
417
            );
418
        }
419
420
        //        $form->addElement($descEditor);
421
422
        return $descEditor;
423
    }
424
425
    /**
426
     * @param $fieldname
427
     * @param $table
428
     *
429
     * @return bool
430
     */
431
432
    public function fieldExists(
433
        $fieldname,
434
        $table
435
    ) {
436
        global $xoopsDB;
437
438
        $result = $xoopsDB->queryF("SHOW COLUMNS FROM   ${table} LIKE '${fieldname}'");
439
440
        return $xoopsDB->getRowsNum($result) > 0;
441
    }
442
}
443