Passed
Push — master ( 07a64a...a326ee )
by Michael
02:21
created

SysUtility::truncateHtml()   F

Complexity

Conditions 19
Paths 194

Size

Total Lines 90
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 19
eloc 48
c 1
b 0
f 0
nc 194
nop 5
dl 0
loc 90
rs 3.7333

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
namespace XoopsModules\Marquee\Common;
4
5
/*
6
 Utility Class Definition
7
8
 You may not change or alter any portion of this comment or credits of
9
 supporting developers from this source code or any supporting source code
10
 which is considered copyrighted (c) material of the original comment or credit
11
 authors.
12
13
 This program is distributed in the hope that it will be useful, but
14
 WITHOUT ANY WARRANTY; without even the implied warranty of
15
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
 */
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 MyTextSanitizer;
27
use Xmf\Request;
28
use XoopsFormDhtmlTextArea;
29
use XoopsFormTextArea;
30
use XoopsModules\Marquee\Helper;
31
32
/**
33
 * Class SysUtility
34
 */
35
class SysUtility
36
{
37
    use VersionChecks; //checkVerXoops, checkVerPhp Traits
0 ignored issues
show
introduced by
The trait XoopsModules\Marquee\Common\VersionChecks requires some properties which are not provided by XoopsModules\Marquee\Common\SysUtility: $tag_name, $prerelease
Loading history...
38
    use ServerStats; // getServerStats Trait
39
    use FilesManagement; // Files Management Trait
40
41
    //--------------- Common module methods -----------------------------
42
43
    /**
44
     * Access the only instance of this class
45
     *
46
     * @return \XoopsModules\Marquee\Common\SysUtility
47
     *
48
     */
49
    public static function getInstance()
50
    {
51
        static $instance;
52
        if (null === $instance) {
53
            $instance = new static();
54
        }
55
56
        return $instance;
57
    }
58
59
    /**
60
     * @param $text
61
     * @param $form_sort
62
     * @return string
63
     */
64
    public static function selectSorting($text, $form_sort)
65
    {
66
        global $start, $order, $file_cat, $sort, $xoopsModule;
67
68
        $select_view   = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $select_view is dead and can be removed.
Loading history...
69
        $moduleDirName = basename(dirname(__DIR__));
0 ignored issues
show
Unused Code introduced by
The assignment to $moduleDirName is dead and can be removed.
Loading history...
70
        /** @var Helper $helper */
71
        $helper = Helper::getInstance();
72
73
        //$pathModIcon16 = XOOPS_URL . '/modules/' . $moduleDirName . '/' . $helper->getConfig('modicons16');
74
        $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

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

334
            $descEditor = new \XoopsFormDhtmlTextArea(ucfirst($options['name']), $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

334
            $descEditor = new \XoopsFormDhtmlTextArea(ucfirst($options['name']), $options['name'], $options['value'], '100%', /** @scrutinizer ignore-type */ '100%');
Loading history...
335
        }
336
337
        //        $form->addElement($descEditor);
338
339
        return $descEditor;
340
    }
341
342
    /**
343
     * @param string $fieldname
344
     * @param string $table
345
     *
346
     * @return bool
347
     */
348
    public static function fieldExists($fieldname, $table)
349
    {
350
        global $xoopsDB;
351
        $result = $xoopsDB->queryF("SHOW COLUMNS FROM   $table LIKE '$fieldname'");
352
353
        return ($xoopsDB->getRowsNum($result) > 0);
354
    }
355
356
    /**
357
     * Function responsible for checking if a directory exists, we can also write in and create an index.html file
358
     *
359
     * @param string $folder The full path of the directory to check
360
     */
361
    public static function prepareFolder($folder)
362
    {
363
        try {
364
            if (!@mkdir($folder) && !is_dir($folder)) {
365
                throw new \RuntimeException(sprintf('Unable to create the %s directory', $folder));
366
            }
367
            file_put_contents($folder . '/index.html', '<script>history.go(-1);</script>');
368
        } catch (\Exception $e) {
369
            echo 'Caught exception: ', $e->getMessage(), "\n", '<br>';
370
        }
371
    }
372
}
373