Passed
Branch master (1c832c)
by Michael
05:44 queued 44s
created

SysUtility::prepareFolder()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 6
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 9
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace XoopsModules\Publisher\Common;
6
7
/*
8
 Utility Class Definition
9
10
 You may not change or alter any portion of this comment or credits of
11
 supporting developers from this source code or any supporting source code
12
 which is considered copyrighted (c) material of the original comment or credit
13
 authors.
14
15
 This program is distributed in the hope that it will be useful, but
16
 WITHOUT ANY WARRANTY; without even the implied warranty of
17
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
 */
19
20
/**
21
 * @license      https://www.fsf.org/copyleft/gpl.html GNU public license
22
 * @copyright    https://xoops.org 2000-2020 &copy; XOOPS Project
23
 * @author       ZySpec <[email protected]>
24
 * @author       Mamba <[email protected]>
25
 */
26
27
use MyTextSanitizer;
28
use XoopsFormDhtmlTextArea;
29
use XoopsFormTextArea;
30
use XoopsModules\Publisher;
31
use XoopsModules\Publisher\Helper;
32
33
/**
34
 * Class SysUtility
35
 */
36
class SysUtility
37
{
38
    use VersionChecks;    //checkVerXoops, checkVerPhp Traits
0 ignored issues
show
introduced by
The trait XoopsModules\Publisher\Common\VersionChecks requires some properties which are not provided by XoopsModules\Publisher\Common\SysUtility: $tag_name, $prerelease
Loading history...
39
    use ServerStats;    // getServerStats Trait
40
    use FilesManagement;    // Files Management Trait
41
    use ModuleStats;    // ModuleStats Trait
0 ignored issues
show
Bug introduced by
The trait XoopsModules\Publisher\Common\ModuleStats requires the property $moduleStats which is not provided by XoopsModules\Publisher\Common\SysUtility.
Loading history...
42
43
    /**
44
     * truncateHtml can truncate a string up to a number of characters while preserving whole words and HTML tags
45
     * www.gsdesign.ro/blog/cut-html-string-without-breaking-the-tags
46
     * www.cakephp.org
47
     *
48
     * @param string $text         String to truncate.
49
     * @param int    $length       Length of returned string, including ellipsis.
50
     * @param string $ending       Ending to be appended to the trimmed string.
51
     * @param bool   $exact        If false, $text will not be cut mid-word
52
     * @param bool   $considerHtml If true, HTML tags would be handled correctly
53
     *
54
     * @return string Trimmed string.
55
     */
56
    public static function truncateHtml($text, $length = 100, $ending = '...', $exact = false, $considerHtml = true)
57
    {
58
        if ($considerHtml) {
59
            // if the plain text is shorter than the maximum length, return the whole text
60
            if (mb_strlen(\preg_replace('/<.*?' . '>/', '', $text)) <= $length) {
61
                return $text;
62
            }
63
            // splits all html-tags to scanable lines
64
            \preg_match_all('/(<.+?' . '>)?([^<>]*)/s', $text, $lines, \PREG_SET_ORDER);
65
            $totalLength = mb_strlen($ending);
66
            $openTags    = [];
67
            $truncate    = '';
68
            foreach ($lines as $lineMatchings) {
69
                // if there is any html-tag in this line, handle it and add it (uncounted) to the output
70
                if (!empty($lineMatchings[1])) {
71
                    // if it's an "empty element" with or without xhtml-conform closing slash
72
                    if (\preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $lineMatchings[1])) {
73
                        // do nothing
74
                        // if tag is a closing tag
75
                    } elseif (\preg_match('/^<\s*\/(\S+?)\s*>$/s', $lineMatchings[1], $tagMatchings)) {
76
                        // delete tag from $openTags list
77
                        $pos = \array_search($tagMatchings[1], $openTags, true);
78
                        if (false !== $pos) {
79
                            unset($openTags[$pos]);
80
                        }
81
                        // if tag is an opening tag
82
                    } elseif (\preg_match('/^<\s*([^\s>!]+).*?' . '>$/s', $lineMatchings[1], $tagMatchings)) {
83
                        // add tag to the beginning of $openTags list
84
                        \array_unshift($openTags, mb_strtolower($tagMatchings[1]));
85
                    }
86
                    // add html-tag to $truncate'd text
87
                    $truncate .= $lineMatchings[1];
88
                }
89
                // calculate the length of the plain text part of the line; handle entities as one character
90
                $content_length = mb_strlen(\preg_replace('/&[0-9a-z]{2,8};|&#\d{1,7};|[0-9a-f]{1,6};/i', ' ', $lineMatchings[2]));
91
                if ($totalLength + $content_length > $length) {
92
                    // the number of characters which are left
93
                    $left           = $length - $totalLength;
94
                    $entitiesLength = 0;
95
                    // search for html entities
96
                    if (\preg_match_all('/&[0-9a-z]{2,8};|&#\d{1,7};|[0-9a-f]{1,6};/i', $lineMatchings[2], $entities, \PREG_OFFSET_CAPTURE)) {
97
                        // calculate the real length of all entities in the legal range
98
                        foreach ($entities[0] as $entity) {
99
                            if ($left >= $entity[1] + 1 - $entitiesLength) {
100
                                $left--;
101
                                $entitiesLength += mb_strlen($entity[0]);
102
                            } else {
103
                                // no more characters left
104
                                break;
105
                            }
106
                        }
107
                    }
108
                    $truncate .= mb_substr($lineMatchings[2], 0, $left + $entitiesLength);
109
                    // maximum lenght is reached, so get off the loop
110
                    break;
111
                }
112
                $truncate    .= $lineMatchings[2];
113
                $totalLength += $content_length;
114
115
                // if the maximum length is reached, get off the loop
116
                if ($totalLength >= $length) {
117
                    break;
118
                }
119
            }
120
        } else {
121
            if (mb_strlen($text) <= $length) {
122
                return $text;
123
            }
124
            $truncate = mb_substr($text, 0, $length - mb_strlen($ending));
125
        }
126
        // if the words shouldn't be cut in the middle...
127
        if (!$exact) {
128
            // ...search the last occurance of a space...
129
            $spacepos = mb_strrpos($truncate, ' ');
130
            if (isset($spacepos)) {
131
                // ...and cut the text in this position
132
                $truncate = mb_substr($truncate, 0, $spacepos);
133
            }
134
        }
135
        // add the defined ending to the text
136
        $truncate .= $ending;
137
        if ($considerHtml) {
138
            // close all unclosed html-tags
139
            foreach ($openTags as $tag) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $openTags does not seem to be defined for all execution paths leading up to this point.
Loading history...
140
                $truncate .= '</' . $tag . '>';
141
            }
142
        }
143
144
        return $truncate;
145
    }
146
147
    /**
148
     * @param null|\Helper $helper
0 ignored issues
show
Bug introduced by
The type Helper was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
149
     * @param array|null   $options
150
     * @return \XoopsFormDhtmlTextArea|\XoopsFormEditor
151
     */
152
    public static function getEditor($helper = null, $options = null)
153
    {
154
        /** @var Helper $helper */
155
        if (null === $options) {
156
            $options           = [];
157
            $options['name']   = 'Editor';
158
            $options['value']  = 'Editor';
159
            $options['rows']   = 10;
160
            $options['cols']   = '100%';
161
            $options['width']  = '100%';
162
            $options['height'] = '400px';
163
        }
164
165
        if (null === $helper) {
166
            $helper = Helper::getInstance();
167
        }
168
169
        $isAdmin = $helper->isUserAdmin();
170
171
        if (\class_exists('XoopsFormEditor')) {
172
            if ($isAdmin) {
173
                $descEditor = new \XoopsFormEditor(\ucfirst($options['name']), $helper->getConfig('editorAdmin'), $options, $nohtml = false, $onfailure = 'textarea');
174
            } else {
175
                $descEditor = new \XoopsFormEditor(\ucfirst($options['name']), $helper->getConfig('editorUser'), $options, $nohtml = false, $onfailure = 'textarea');
176
            }
177
        } else {
178
            $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

178
            $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

178
            $descEditor = new \XoopsFormDhtmlTextArea(\ucfirst($options['name']), $options['name'], $options['value'], '100%', /** @scrutinizer ignore-type */ '100%');
Loading history...
179
        }
180
181
        //        $form->addElement($descEditor);
182
183
        return $descEditor;
184
    }
185
186
    /**
187
     * @param $fieldname
188
     * @param $table
189
     *
190
     * @return bool
191
     */
192
    public static function fieldExists($fieldname, $table)
193
    {
194
        global $xoopsDB;
195
        $result = $xoopsDB->queryF("SHOW COLUMNS FROM   $table LIKE '$fieldname'");
196
197
        return ($xoopsDB->getRowsNum($result) > 0);
198
    }
199
200
    /**
201
     * @param array|string $tableName
202
     * @param int          $id_field
203
     * @param int          $id
204
     *
205
     * @return mixed
206
     */
207
    public static function cloneRecord($tableName, $id_field, $id)
208
    {
209
        $new_id = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $new_id is dead and can be removed.
Loading history...
210
        $table  = $GLOBALS['xoopsDB']->prefix($tableName);
211
        // copy content of the record you wish to clone
212
        $sql       = "SELECT * FROM $table WHERE $id_field='$id' ";
213
        $tempTable = $GLOBALS['xoopsDB']->fetchArray($GLOBALS['xoopsDB']->query($sql), \MYSQLI_ASSOC);
214
        if (!$tempTable) {
215
            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...
216
        }
217
        // set the auto-incremented id's value to blank.
218
        unset($tempTable[$id_field]);
219
        // insert cloned copy of the original  record
220
        $sql    = "INSERT INTO $table (" . \implode(', ', \array_keys($tempTable)) . ") VALUES ('" . \implode("', '", \array_values($tempTable)) . "')";
221
        $result = $GLOBALS['xoopsDB']->queryF($sql);
222
        if (!$result) {
223
            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...
224
        }
225
        // Return the new id
226
        $new_id = $GLOBALS['xoopsDB']->getInsertId();
227
228
        return $new_id;
229
    }
230
231
    /**
232
     * Function responsible for checking if a directory exists, we can also write in and create an index.html file
233
     *
234
     * @param string $folder The full path of the directory to check
235
     */
236
    public static function prepareFolder($folder)
237
    {
238
        try {
239
            if (!@\mkdir($folder) && !\is_dir($folder)) {
240
                throw new \RuntimeException(\sprintf('Unable to create the %s directory', $folder));
241
            }
242
            file_put_contents($folder . '/index.html', '<script>history.go(-1);</script>');
243
        } catch (\Exception $e) {
244
            echo 'Caught exception: ', $e->getMessage(), "\n", '<br>';
245
        }
246
    }
247
248
249
    /**
250
     * @param string $tablename
251
     *
252
     * @return bool
253
     */
254
    public static function tableExists($tablename)
255
    {
256
        $result = $GLOBALS['xoopsDB']->queryF("SHOW TABLES LIKE '$tablename'");
257
258
        return $GLOBALS['xoopsDB']->getRowsNum($result) > 0;
259
    }
260
}
261