SysUtility::truncateHtml()   F
last analyzed

Complexity

Conditions 19
Paths 194

Size

Total Lines 87
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

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

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 declare(strict_types=1);
2
3
namespace XoopsModules\Suico\Common;
4
5
/*
6
 Utility Class Definition
7
 You may not change or alter any portion of this comment or credits of
8
 supporting developers from this source code or any supporting source code
9
 which is considered copyrighted (c) material of the original comment or credit
10
 authors.
11
12
 This program is distributed in the hope that it will be useful, but
13
 WITHOUT ANY WARRANTY; without even the implied warranty of
14
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
 */
16
17
/**
18
 * @license      GNU GPL 2.0 or later (https://www.gnu.org/licenses/gpl-2.0.html)
19
 * @copyright    https://xoops.org 2000-2020 &copy; XOOPS Project
20
 * @author       ZySpec <[email protected]>
21
 * @author       Mamba <[email protected]>
22
 */
23
24
use Xmf\Request;
25
use XoopsFormDhtmlTextArea;
26
use XoopsFormEditor;
27
use XoopsModules\Suico\{
28
    Helper
29
};
30
/** @var Helper $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
    //--------------- Custom module methods -----------------------------
43
44
    /**
45
     * @param $text
46
     * @param $form_sort
47
     * @return string
48
     */
49
    public static function selectSorting($text, $form_sort)
50
    {
51
        global $start, $order, $file_cat, $sort, $xoopsModule;
52
        $select_view   = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $select_view is dead and can be removed.
Loading history...
53
        $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...
54
        $helper        = Helper::getInstance();
55
        //        $pathModIcon16 = XOOPS_URL . '/modules/' . $moduleDirName . '/' . $helper->getModule()->getInfo('modicons16');
56
        $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

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

335
                /** @scrutinizer ignore-type */ '100%',
Loading history...
336
                '100%'
0 ignored issues
show
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

336
                /** @scrutinizer ignore-type */ '100%'
Loading history...
337
            );
338
        }
339
        //        $form->addElement($descEditor);
340
        return $descEditor;
341
    }
342
343
    /**
344
     * @param $fieldname
345
     * @param $table
346
     *
347
     * @return bool
348
     */
349
    public function fieldExists(
350
        $fieldname,
351
        $table
352
    ) {
353
        global $xoopsDB;
354
        $result = $xoopsDB->queryF("SHOW COLUMNS FROM   {$table} LIKE '{$fieldname}'");
355
356
        return $xoopsDB->getRowsNum($result) > 0;
357
    }
358
}
359