Passed
Push — master ( b5dddf...91d417 )
by Richard
09:12
created

MyTextSanitizer::codeConv()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php
2
/**
3
 * XOOPS TextSanitizer extension
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
13
 * @license             GNU GPL 2 (http://www.gnu.org/licenses/gpl-2.0.html)
14
 * @package             class
15
 * @since               2.0.0
16
 * @author              Kazumi Ono (http://www.myweb.ne.jp/, http://jp.xoops.org/)
17
 * @author              Goghs Cheng (http://www.eqiao.com, http://www.devbeez.com/)
18
 * @author              Taiwen Jiang <[email protected]>
19
 */
20
21
/**
22
 * Abstract class for extensions
23
 *
24
 * @author              Taiwen Jiang <[email protected]>
25
 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
26
 */
27
class MyTextSanitizerExtension
28
{
29
    public $instance;
30
    public $ts;
31
    public $config;
32
    public $image_path;
33
34
    /**
35
     * Constructor
36
     *
37
     * @param MyTextSanitizer $ts
38
     */
39
    public function __construct(MyTextSanitizer $ts)
40
    {
41
        $this->ts         = $ts;
42
        $this->image_path = XOOPS_URL . '/images/form';
43
    }
44
45
    /**
46
     * loadConfig
47
     *
48
     * @param  string $path
49
     * @return string
50
     */
51
    public static function loadConfig($path = null)
52
    {
53
        $ts   = MyTextSanitizer::getInstance();
54
        $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
55
        if (false === strpos($path, '/')) {
56
            if (is_dir($ts->path_basic . '/' . $path)) {
57
                $path = $ts->path_basic . '/' . $path;
58
            } else {
59
                if (is_dir($ts->path_plugin . '/' . $path)) {
60
                    $path = $ts->path_plugin . '/' . $path;
61
                }
62
            }
63
        }
64
        $config_default = array();
65
        $config_custom  = array();
66
        if (file_exists($path . '/config.php')) {
67
            $config_default = include $path . '/config.php';
68
        }
69
        if (file_exists($path . '/config.custom.php')) {
70
            $config_custom = include $path . '/config.custom.php';
71
        }
72
73
        return self::mergeConfig($config_default, $config_custom);
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::mergeConfig...efault, $config_custom) returns the type array which is incompatible with the documented return type string.
Loading history...
74
    }
75
76
    /**
77
     * Merge Config
78
     *
79
     * @param  array $config_default
80
     * @param  array $config_custom
81
     * @return array
82
     */
83
    public static function mergeConfig($config_default, $config_custom)
84
    {
85
        if (is_array($config_custom)) {
0 ignored issues
show
introduced by
The condition is_array($config_custom) is always true.
Loading history...
86
            foreach ($config_custom as $key => $val) {
87
                if (is_array($config_default[$key])) {
88
                    $config_default[$key] = self::mergeConfig($config_default[$key], $config_custom[$key]);
89
                } else {
90
                    $config_default[$key] = $val;
91
                }
92
            }
93
        }
94
95
        return $config_default;
96
    }
97
98
    /**
99
     * encode
100
     *
101
     * @param string $textarea_id id attribute of text area
102
     *
103
     * @return array
104
     */
105
    public function encode($textarea_id)
0 ignored issues
show
Unused Code introduced by
The parameter $textarea_id is not used and could be removed. ( Ignorable by Annotation )

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

105
    public function encode(/** @scrutinizer ignore-unused */ $textarea_id)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
106
    {
107
        return array();
108
    }
109
110
    /**
111
     * decode
112
     *
113
     * @return Null
114
     */
115
    public static function decode($url, $width, $height)
0 ignored issues
show
Unused Code introduced by
The parameter $width is not used and could be removed. ( Ignorable by Annotation )

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

115
    public static function decode($url, /** @scrutinizer ignore-unused */ $width, $height)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $height is not used and could be removed. ( Ignorable by Annotation )

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

115
    public static function decode($url, $width, /** @scrutinizer ignore-unused */ $height)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
116
    {
117
        return null;
118
    }
119
}
120
121
/**
122
 * Class to "clean up" text for various uses
123
 *
124
 * <strong>Singleton</strong>
125
 *
126
 * @package       kernel
127
 * @subpackage    core
128
 * @author        Kazumi Ono <[email protected]>
129
 * @author        Taiwen Jiang <[email protected]>
130
 * @author        Goghs Cheng
131
 * @copyright (c) 2000-2016 XOOPS Project - www.xoops.org
132
 */
133
class MyTextSanitizer
134
{
135
    /**
136
     *
137
     * @var array
138
     */
139
    public $smileys = array();
140
141
    /**
142
     */
143
    public $censorConf;
144
145
    /**
146
     *
147
     * @var holding reference to text
0 ignored issues
show
Bug introduced by
The type holding 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...
148
     */
149
    public $text         = '';
150
    public $patterns     = array();
151
    public $replacements = array();
152
153
    //mb------------------------------
154
    public $callbackPatterns = array();
155
    public $callbacks        = array();
156
    //mb------------------------------
157
158
    public $path_basic;
159
    public $path_plugin;
160
161
    public $config;
162
163
    /**
164
     * Constructor of this class
165
     *
166
     * Gets allowed html tags from admin config settings
167
     * <br> should not be allowed since nl2br will be used
168
     * when storing data.
169
     *
170
     * @access private
171
     */
172
173
    public function __construct()
174
    {
175
        $this->path_basic  = XOOPS_ROOT_PATH . '/class/textsanitizer';
176
        $this->path_plugin = XOOPS_ROOT_PATH . '/Frameworks/textsanitizer';
177
        $this->config      = $this->loadConfig();
178
    }
179
180
    /**
181
     * Enter description here...
182
     *
183
     * @param  string $name
184
     * @return array
185
     */
186
    public function loadConfig($name = null)
187
    {
188
        if (!empty($name)) {
189
            return MyTextSanitizerExtension::loadConfig($name);
0 ignored issues
show
Bug Best Practice introduced by
The expression return MyTextSanitizerExtension::loadConfig($name) returns the type string which is incompatible with the documented return type array.
Loading history...
190
        }
191
        $config_default = include $this->path_basic . '/config.php';
192
        $config_custom  = array();
193
        if (file_exists($file = $this->path_basic . '/config.custom.php')) {
194
            $config_custom = include $file;
195
        }
196
197
        return $this->mergeConfig($config_default, $config_custom);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->mergeConfi...efault, $config_custom) returns the type unknown which is incompatible with the documented return type array.
Loading history...
198
    }
199
200
    /**
201
     * Enter description here...
202
     *
203
     * @param  array $config_default
204
     * @param  array $config_custom
205
     * @return unknown
0 ignored issues
show
Bug introduced by
The type unknown 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...
206
     */
207
    public function mergeConfig($config_default, $config_custom)
208
    {
209
        if (is_array($config_custom)) {
0 ignored issues
show
introduced by
The condition is_array($config_custom) is always true.
Loading history...
210
            foreach ($config_custom as $key => $val) {
211
                if (isset($config_default[$key]) && is_array($config_default[$key])) {
212
                    $config_default[$key] = $this->mergeConfig($config_default[$key], $config_custom[$key]);
213
                } else {
214
                    $config_default[$key] = $val;
215
                }
216
            }
217
        }
218
219
        return $config_default;
220
    }
221
222
    /**
223
     * Access the only instance of this class
224
     *
225
     * @return object
226
     * @static
227
     * @staticvar object
228
     */
229
    public static function getInstance()
230
    {
231
        static $instance;
232
        if (!isset($instance)) {
233
            $instance = new MyTextSanitizer();
234
        }
235
236
        return $instance;
237
    }
238
239
    /**
240
     * Get the smileys
241
     *
242
     * @param bool $isAll TRUE for all smileys, FALSE for smileys with display = 1
243
     *
244
     * @return array
245
     */
246
    public function getSmileys($isAll = true)
247
    {
248
        if (count($this->smileys) == 0) {
249
            /* @var $xoopsDB XoopsMySQLDatabase */
250
            $xoopsDB = XoopsDatabaseFactory::getDatabaseConnection();
251
            if ($getsmiles = $xoopsDB->query('SELECT * FROM ' . $xoopsDB->prefix('smiles'))) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $getsmiles is correct as $xoopsDB->query('SELECT ...psDB->prefix('smiles')) targeting XoopsMySQLDatabase::query() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
252
                while (false !== ($smiles = $xoopsDB->fetchArray($getsmiles))) {
0 ignored issues
show
Bug introduced by
$getsmiles of type void is incompatible with the type mysqli_result expected by parameter $result of XoopsMySQLDatabase::fetchArray(). ( Ignorable by Annotation )

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

252
                while (false !== ($smiles = $xoopsDB->fetchArray(/** @scrutinizer ignore-type */ $getsmiles))) {
Loading history...
253
                    $this->smileys[] = $smiles;
254
                }
255
            }
256
        }
257
        if ($isAll) {
258
            return $this->smileys;
259
        }
260
261
        $smileys = array();
262
        foreach ($this->smileys as $smile) {
263
            if (empty($smile['display'])) {
264
                continue;
265
            }
266
            $smileys[] = $smile;
267
        }
268
269
        return $smileys;
270
    }
271
272
    /**
273
     * Replace emoticons in the message with smiley images
274
     *
275
     * @param  string $message
276
     * @return string
277
     */
278
    public function smiley($message)
279
    {
280
        $smileys = $this->getSmileys();
281
        foreach ($smileys as $smile) {
282
            $message = str_replace($smile['code'], '<img class="imgsmile" src="' . XOOPS_UPLOAD_URL . '/' . htmlspecialchars($smile['smile_url']) . '" alt="" />', $message);
283
        }
284
285
        return $message;
286
    }
287
288
    /**
289
     * @param $match
290
     *
291
     * @return string
292
     */
293
    public function makeClickableCallback01($match)
294
    {
295
        return $match[1] . "<a href=\"$match[2]://$match[3]\" title=\"$match[2]://$match[3]\" rel=\"external\">$match[2]://" . $this->truncate($match[3]) . '</a>';
296
    }
297
298
    /**
299
     * @param $match
300
     *
301
     * @return string
302
     */
303
    public function makeClickableCallback02($match)
304
    {
305
        return $match[1] . "<a href=\"http://www.$match[2]$match[6]\" title=\"www.$match[2]$match[6]\" rel=\"external\">" . $this->truncate('www.' . $match[2] . $match[6]) . '</a>';
306
    }
307
308
    /**
309
     * @param $match
310
     *
311
     * @return string
312
     */
313
    public function makeClickableCallback03($match)
314
    {
315
        return $match[1] . "<a href=\"ftp://ftp.$match[2].$match[3]\" title=\"ftp.$match[2].$match[3]\" rel=\"external\">" . $this->truncate('ftp.' . $match[2] . $match[3]) . '</a>';
316
    }
317
318
    /**
319
     * @param $match
320
     *
321
     * @return string
322
     */
323
    public function makeClickableCallback04($match)
324
    {
325
        return $match[1] . "<a href=\"mailto:$match[2]@$match[3]\" title=\"$match[2]@$match[3]\">" . $this->truncate($match[2] . '@' . $match[3]) . '</a>';
326
    }
327
328
    /**
329
     * Make links in the text clickable
330
     *
331
     * @param  string $text
332
     * @return string
333
     */
334
    public function makeClickable(&$text)
335
    {
336
        $text1 = $text;
337
338
        $valid_chars = "a-z0-9\/\-_+=.~!%@?#&;:$\|";
339
        $end_chars   = "a-z0-9\/\-_+=~!%@?#&;:$\|";
340
341
        //        $patterns   = array();
342
        //        $replacements   = array();
343
        //
344
        //        $patterns[]     = "/(^|[^]_a-z0-9-=\"'\/])([a-z]+?):\/\/([{$valid_chars}]+[{$end_chars}])/ei";
345
        //        $replacements[] = "'\\1<a href=\"\\2://\\3\" title=\"\\2://\\3\" rel=\"external\">\\2://'.MyTextSanitizer::truncate( '\\3' ).'</a>'";
346
        //
347
        //
348
        //        $patterns[]     = "/(^|[^]_a-z0-9-=\"'\/:\.])www\.((([a-zA-Z0-9\-]*\.){1,}){1}([a-zA-Z]{2,6}){1})((\/([a-zA-Z0-9\-\._\?\,\'\/\\+&%\$#\=~])*)*)/ei";
349
        //        $replacements[] = "'\\1<a href=\"http://www.\\2\\6\" title=\"www.\\2\\6\" rel=\"external\">'.MyTextSanitizer::truncate( 'www.\\2\\6' ).'</a>'";
350
        //
351
        //        $patterns[]     = "/(^|[^]_a-z0-9-=\"'\/])ftp\.([a-z0-9\-]+)\.([{$valid_chars}]+[{$end_chars}])/ei";
352
        //        $replacements[] = "'\\1<a href=\"ftp://ftp.\\2.\\3\" title=\"ftp.\\2.\\3\" rel=\"external\">'.MyTextSanitizer::truncate( 'ftp.\\2.\\3' ).'</a>'";
353
        //
354
        //        $patterns[]     = "/(^|[^]_a-z0-9-=\"'\/:\.])([-_a-z0-9\'+*$^&%=~!?{}]++(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*+)@((?:(?![-.])[-a-z0-9.]+(?<![-.])\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})(?::\d++)?)/ei";
355
        //        $replacements[] = "'\\1<a href=\"mailto:\\2@\\3\" title=\"\\2@\\3\">'.MyTextSanitizer::truncate( '\\2@\\3' ).'</a>'";
356
        //
357
        //        $text = preg_replace($patterns, $replacements, $text);
358
        //
359
        //----------------------------------------------------------------------------------
360
361
        $pattern = "/(^|[^]_a-z0-9-=\"'\/])([a-z]+?):\/\/([{$valid_chars}]+[{$end_chars}])/i";
362
        $text1   = preg_replace_callback($pattern, 'self::makeClickableCallback01', $text1);
363
364
        $pattern = "/(^|[^]_a-z0-9-=\"'\/:\.])www\.((([a-zA-Z0-9\-]*\.){1,}){1}([a-zA-Z]{2,6}){1})((\/([a-zA-Z0-9\-\._\?\,\'\/\\+&%\$#\=~])*)*)/i";
365
        $text1   = preg_replace_callback($pattern, 'self::makeClickableCallback02', $text1);
366
367
        $pattern = "/(^|[^]_a-z0-9-=\"'\/])ftp\.([a-z0-9\-]+)\.([{$valid_chars}]+[{$end_chars}])/i";
368
        $text1   = preg_replace_callback($pattern, 'self::makeClickableCallback03', $text1);
369
370
        $pattern = "/(^|[^]_a-z0-9-=\"'\/:\.])([-_a-z0-9\'+*$^&%=~!?{}]++(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*+)@((?:(?![-.])[-a-z0-9.]+(?<![-.])\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})(?::\d++)?)/i";
371
        $text1   = preg_replace_callback($pattern, 'self::makeClickableCallback04', $text1);
372
373
        return $text1;
374
    }
375
376
    /**
377
     * MyTextSanitizer::truncate()
378
     *
379
     * @param  mixed $text
380
     * @return mixed|string
381
     */
382
    public function truncate($text)
383
    {
384
        $instance = MyTextSanitizer::getInstance();
385
        if (empty($text) || empty($instance->config['truncate_length']) || strlen($text) < $instance->config['truncate_length']) {
386
            return $text;
387
        }
388
        $len = floor($instance->config['truncate_length'] / 2);
389
        $ret = substr($text, 0, $len) . ' ... ' . substr($text, 5 - $len);
0 ignored issues
show
Bug introduced by
5 - $len of type double is incompatible with the type integer expected by parameter $start of substr(). ( Ignorable by Annotation )

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

389
        $ret = substr($text, 0, $len) . ' ... ' . substr($text, /** @scrutinizer ignore-type */ 5 - $len);
Loading history...
Bug introduced by
$len of type double is incompatible with the type integer expected by parameter $length of substr(). ( Ignorable by Annotation )

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

389
        $ret = substr($text, 0, /** @scrutinizer ignore-type */ $len) . ' ... ' . substr($text, 5 - $len);
Loading history...
390
391
        return $ret;
392
    }
393
394
    /**
395
     * Replace XoopsCodes with their equivalent HTML formatting
396
     *
397
     * @param  string   $text
398
     * @param  bool|int $allowimage Allow images in the text?
399
     *                              On FALSE, uses links to images.
400
     * @return string
401
     */
402
    public function &xoopsCodeDecode(&$text, $allowimage = 1)
403
    {
404
        $patterns       = array();
405
        $replacements   = array();
406
        $patterns[]     = "/\[siteurl=(['\"]?)([^\"'<>]*)\\1](.*)\[\/siteurl\]/sU";
407
        $replacements[] = '<a href="' . XOOPS_URL . '/\\2" title="">\\3</a>';
408
        $patterns[]     = "/\[url=(['\"]?)(http[s]?:\/\/[^\"'<>]*)\\1](.*)\[\/url\]/sU";
409
        $replacements[] = '<a href="\\2" rel="external" title="">\\3</a>';
410
        $patterns[]     = "/\[url=(['\"]?)(ftp?:\/\/[^\"'<>]*)\\1](.*)\[\/url\]/sU";
411
        $replacements[] = '<a href="\\2" rel="external" title="">\\3</a>';
412
        $patterns[]     = "/\[url=(['\"]?)([^'\"<>]*)\\1](.*)\[\/url\]/sU";
413
        $replacements[] = '<a href="http://\\2" rel="external" title="">\\3</a>';
414
        $patterns[]     = "/\[color=(['\"]?)([a-zA-Z0-9]*)\\1](.*)\[\/color\]/sU";
415
        $replacements[] = '<span style="color: #\\2;">\\3</span>';
416
        $patterns[]     = "/\[size=(['\"]?)([a-z0-9-]*)\\1](.*)\[\/size\]/sU";
417
        $replacements[] = '<span style="font-size: \\2;">\\3</span>';
418
        $patterns[]     = "/\[font=(['\"]?)([^;<>\*\(\)\"']*)\\1](.*)\[\/font\]/sU";
419
        $replacements[] = '<span style="font-family: \\2;">\\3</span>';
420
        $patterns[]     = "/\[email]([^;<>\*\(\)\"']*)\[\/email\]/sU";
421
        $replacements[] = '<a href="mailto:\\1" title="">\\1</a>';
422
423
        $patterns[]     = "/\[b](.*)\[\/b\]/sU";
424
        $replacements[] = '<strong>\\1</strong>';
425
        $patterns[]     = "/\[i](.*)\[\/i\]/sU";
426
        $replacements[] = '<em>\\1</em>';
427
        $patterns[]     = "/\[u](.*)\[\/u\]/sU";
428
        $replacements[] = '<span style="text-decoration: underline;">\\1</span>';
429
        $patterns[]     = "/\[d](.*)\[\/d\]/sU";
430
        $replacements[] = '<del>\\1</del>';
431
        $patterns[]     = "/\[center](.*)\[\/center\]/sU";
432
        $replacements[] = '<div style="text-align: center;">\\1</div>';
433
        $patterns[]     = "/\[left](.*)\[\/left\]/sU";
434
        $replacements[] = '<div style="text-align: left;">\\1</div>';
435
        $patterns[]     = "/\[right](.*)\[\/right\]/sU";
436
        $replacements[] = '<div style="text-align: right;">\\1</div>';
437
438
        $this->text         = $text;
0 ignored issues
show
Documentation Bug introduced by
It seems like $text of type string is incompatible with the declared type holding of property $text.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
439
        $this->patterns     = $patterns;
440
        $this->replacements = $replacements;
441
442
        $this->config['allowimage'] = $allowimage;
443
        $this->executeExtensions();
444
445
        $text = preg_replace($this->patterns, $this->replacements, $this->text);
446
        //-------------------------------------------------------------------------------
447
        $count = count($this->callbackPatterns);
448
449
        for ($i = 0; $i < $count; ++$i) {
450
            $text = preg_replace_callback($this->callbackPatterns[$i], $this->callbacks[$i], $text);
451
        }
452
        //------------------------------------------------------------------------------
453
        $text = $this->quoteConv($text);
454
455
        return $text;
456
    }
457
458
    /**
459
     * Convert quote tags
460
     *
461
     * @param  string $text
462
     * @return string
463
     */
464
    public function quoteConv($text)
465
    {
466
        //look for both open and closing tags in the correct order
467
        $pattern     = "/\[quote](.*)\[\/quote\]/sU";
468
        $replacement = _QUOTEC . '<div class="xoopsQuote"><blockquote>\\1</blockquote></div>';
469
470
        $text = preg_replace($pattern, $replacement, $text, -1, $count);
471
        //no more matches, return now
472
        if (!$count) {
473
            return $text;
474
        }
475
476
        //new matches could have been created, keep doing it until we have no matches
477
        return $this->quoteConv($text);
478
    }
479
480
    /**
481
     * A quick solution for filtering XSS scripts
482
     *
483
     * @TODO : To be improved
484
     * @param $text
485
     * @return mixed
486
     */
487
    public function filterXss($text)
488
    {
489
        $patterns       = array();
490
        $replacements   = array();
491
        $text           = str_replace("\x00", '', $text);
492
        $c              = "[\x01-\x1f]*";
493
        $patterns[]     = "/\bj{$c}a{$c}v{$c}a{$c}s{$c}c{$c}r{$c}i{$c}p{$c}t{$c}[\s]*:/si";
494
        $replacements[] = 'javascript;';
495
        $patterns[]     = "/\ba{$c}b{$c}o{$c}u{$c}t{$c}[\s]*:/si";
496
        $replacements[] = 'about;';
497
        $patterns[]     = "/\bx{$c}s{$c}s{$c}[\s]*:/si";
498
        $replacements[] = 'xss;';
499
        $text           = preg_replace($patterns, $replacements, $text);
500
501
        return $text;
502
    }
503
504
    /**
505
     * Convert linebreaks to <br> tags
506
     *
507
     * @param  string $text
508
     * @return string
509
     */
510
    public function nl2Br($text)
511
    {
512
        return preg_replace('/(\015\012)|(\015)|(\012)/', '<br>', $text);
513
    }
514
515
    /**
516
     * Add slashes to the text if magic_quotes_gpc is turned off.
517
     *
518
     * @param  string $text
519
     * @return string
520
     */
521
    public function addSlashes($text)
522
    {
523
        if (!get_magic_quotes_gpc()) {
524
            $text = addslashes($text);
525
        }
526
527
        return $text;
528
    }
529
530
    /**
531
     * if magic_quotes_gpc is on, stirip back slashes
532
     *
533
     * @param  string $text
534
     * @return string
535
     */
536
    public function stripSlashesGPC($text)
537
    {
538
        if (get_magic_quotes_gpc()) {
539
            $text = stripslashes($text);
540
        }
541
542
        return $text;
543
    }
544
545
    /**
546
     * Convert special characters to HTML entities
547
     *
548
     * @param  string $text    string being converted
549
     * @param  int    $quote_style
550
     * @param  string $charset character set used in conversion
551
     * @param  bool   $double_encode
552
     * @return string
553
     */
554
    public function htmlSpecialChars($text, $quote_style = ENT_QUOTES, $charset = null, $double_encode = true)
555
    {
556
        if (version_compare(phpversion(), '5.2.3', '>=')) {
557
            $text = htmlspecialchars($text, $quote_style, $charset ?: (defined('_CHARSET') ? _CHARSET : 'UTF-8'), $double_encode);
558
        } else {
559
            $text = htmlspecialchars($text, $quote_style);
560
        }
561
562
        return preg_replace(array('/&amp;/i', '/&nbsp;/i'), array('&', '&amp;nbsp;'), $text);
563
    }
564
565
    /**
566
     * Reverses {@link htmlSpecialChars()}
567
     *
568
     * @param  string $text
569
     * @return string
570
     */
571
    public function undoHtmlSpecialChars($text)
572
    {
573
        return preg_replace(array('/&gt;/i', '/&lt;/i', '/&quot;/i', '/&#039;/i', '/&amp;nbsp;/i'), array('>', '<', '"', '\'', '&nbsp;'), $text);
574
    }
575
576
    /**
577
     * Filters textarea form data in DB for display
578
     *
579
     * @param  string   $text
580
     * @param  bool|int $html   allow html?
581
     * @param  bool|int $smiley allow smileys?
582
     * @param  bool|int $xcode  allow xoopscode?
583
     * @param  bool|int $image  allow inline images?
584
     * @param  bool|int $br     convert linebreaks?
585
     * @return string
586
     */
587
    public function &displayTarea($text, $html = 0, $smiley = 1, $xcode = 1, $image = 1, $br = 1)
588
    {
589
        $charset = (defined('_CHARSET') ? _CHARSET : 'UTF-8');
590
        if (function_exists('mb_convert_encoding')) {
591
            $text = mb_convert_encoding($text, $charset, mb_detect_encoding($text, mb_detect_order(), true));
592
        }
593
        if ($html != 1) {
594
            // html not allowed
595
            $text = $this->htmlSpecialChars($text, ENT_COMPAT, $charset);
596
        }
597
        $text = $this->codePreConv($text, $xcode); // Ryuji_edit(2003-11-18)
598
        if ($smiley != 0) {
599
            // process smiley
600
            $text = $this->smiley($text);
601
        }
602
        if ($xcode != 0) {
603
            // decode xcode
604
            if ($image != 0) {
605
                // image allowed
606
                $text =& $this->xoopsCodeDecode($text);
607
            } else {
608
                // image not allowed
609
                $text =& $this->xoopsCodeDecode($text, 0);
610
            }
611
        }
612
        if ($br != 0) {
613
            $text = $this->nl2Br($text);
614
        }
615
        $text = $this->codeConv($text, $xcode);
616
        $text = $this->makeClickable($text);
617
        if (!empty($this->config['filterxss_on_display'])) {
618
            $text = $this->filterXss($text);
619
        }
620
621
        return $text;
622
    }
623
624
    /**
625
     * Filters textarea form data submitted for preview
626
     *
627
     * @param  string   $text
628
     * @param  bool|int $html   allow html?
629
     * @param  bool|int $smiley allow smileys?
630
     * @param  bool|int $xcode  allow xoopscode?
631
     * @param  bool|int $image  allow inline images?
632
     * @param  bool|int $br     convert linebreaks?
633
     * @return string
634
     */
635
    public function &previewTarea($text, $html = 0, $smiley = 1, $xcode = 1, $image = 1, $br = 1)
636
    {
637
        $text = $this->stripSlashesGPC($text);
638
        $text =& $this->displayTarea($text, $html, $smiley, $xcode, $image, $br);
639
640
        return $text;
641
    }
642
643
    /**
644
     * Replaces banned words in a string with their replacements
645
     *
646
     * @param  string $text
647
     * @return string
648
     * @deprecated
649
     */
650
    public function &censorString(&$text)
651
    {
652
        $ret = $this->executeExtension('censor', $text);
653
        if ($ret === false) {
654
            return $text;
655
        }
656
657
        return $ret;
658
    }
659
660
    /**
661
     * MyTextSanitizer::codePreConv()
662
     *
663
     * @param  mixed $text
664
     * @param  mixed $xcode
665
     * @return mixed
666
     */
667
    public function codePreConv($text, $xcode = 1)
668
    {
669
        if ($xcode != 0) {
670
            //            $patterns = "/\[code([^\]]*?)\](.*)\[\/code\]/esU";
671
            //            $replacements = "'[code\\1]'.base64_encode('\\2').'[/code]'";
672
673
            $patterns = "/\[code([^\]]*?)\](.*)\[\/code\]/sU";
674
            $text = preg_replace_callback(
675
                $patterns,
676
                function ($matches) {
677
                    return '[code'. $matches[1] . ']' . base64_encode($matches[2]) . '[/code]';
678
                },
679
                $text
680
            );
681
        }
682
683
        return $text;
684
    }
685
686
    /**
687
     * @param $match
688
     *
689
     * @return string
690
     */
691
    public function codeConvCallback($match)
692
    {
693
        return '<div class="xoopsCode">' . $this->executeExtension('syntaxhighlight', str_replace('\\\"', '\"', base64_decode($match[2])), $match[1]) . '</div>';
694
    }
695
696
    /**
697
     * MyTextSanitizer::codeConv()
698
     *
699
     * @param  mixed $text
700
     * @param  mixed $xcode
701
     * @return mixed
702
     */
703
    public function codeConv($text, $xcode = 1)
704
    {
705
        if (empty($xcode)) {
706
            return $text;
707
        }
708
        $patterns = "/\[code([^\]]*?)\](.*)\[\/code\]/sU";
709
        $text1    = preg_replace_callback($patterns, array($this, 'codeConvCallback'), $text);
710
711
        return $text1;
712
    }
713
714
    /**
715
     * MyTextSanitizer::executeExtensions()
716
     *
717
     * @return bool
718
     */
719
    public function executeExtensions()
720
    {
721
        $extensions = array_filter($this->config['extensions']);
722
        if (empty($extensions)) {
723
            return true;
724
        }
725
        foreach (array_keys($extensions) as $extension) {
726
            $this->executeExtension($extension);
727
        }
728
        return null;
729
    }
730
731
    /**
732
     * MyTextSanitizer::loadExtension()
733
     *
734
     * @param  mixed $name
735
     * @return bool|null
736
     */
737
    public function loadExtension($name)
738
    {
739
        if (file_exists($file = $this->path_basic . '/' . $name . '/' . $name . '.php')) {
740
            include_once $file;
741
        } elseif (file_exists($file = $this->path_plugin . '/' . $name . '/' . $name . '.php')) {
742
            include_once $file;
743
        } else {
744
            return false;
745
        }
746
        $class = 'Myts' . ucfirst($name);
747
        if (!class_exists($class)) {
748
            trigger_error("Extension '{$name}' does not exist", E_USER_WARNING);
749
750
            return false;
751
        }
752
        $extension = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $extension is dead and can be removed.
Loading history...
753
        $extension = new $class($this);
754
755
        return $extension;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extension returns the type object which is incompatible with the documented return type null|boolean.
Loading history...
756
    }
757
758
    /**
759
     * MyTextSanitizer::executeExtension()
760
     *
761
     * @param  mixed $name
762
     * @return mixed
763
     */
764
    public function executeExtension($name)
765
    {
766
        $extension = $this->loadExtension($name);
767
        $args      = array_slice(func_get_args(), 1);
768
        array_unshift($args, $this);
769
770
        return call_user_func_array(array($extension, 'load'), $args);
771
    }
772
773
    /**
774
     * Filter out possible malicious text
775
     * kses project at SF could be a good solution to check
776
     *
777
     * @param  string $text  text to filter
778
     * @param  bool   $force force filtering
779
     * @return string filtered text
780
     */
781
    public function textFilter($text, $force = false)
782
    {
783
        $ret = $this->executeExtension('textfilter', $text, $force);
784
        if ($ret === false) {
785
            return $text;
786
        }
787
788
        return $ret;
789
    }
790
791
    // #################### Deprecated Methods ######################
792
    /**
793
     * *#@+
794
     *
795
     * @deprecated
796
     */
797
798
    /**
799
     * MyTextSanitizer::codeSanitizer()
800
     *
801
     * @param  mixed $str
802
     * @param  mixed $image
803
     * @return mixed|string
804
     */
805
    public function codeSanitizer($str, $image = 1)
806
    {
807
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
808
        $str = $this->htmlSpecialChars(str_replace('\"', '"', base64_decode($str)));
809
        $str =& $this->xoopsCodeDecode($str, $image);
810
811
        return $str;
812
    }
813
814
    /**
815
     * MyTextSanitizer::sanitizeForDisplay()
816
     *
817
     * @param  mixed   $text
818
     * @param  integer $allowhtml
819
     * @param  integer $smiley
820
     * @param  mixed   $bbcode
821
     * @return mixed|string
822
     */
823
    public function sanitizeForDisplay($text, $allowhtml = 0, $smiley = 1, $bbcode = 1)
824
    {
825
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
826
        if ($allowhtml == 0) {
827
            $text = $this->htmlSpecialChars($text);
828
        } else {
829
            // $config =& $GLOBALS['xoopsConfig'];
830
            // $allowed = $config['allowed_html'];
831
            // $text = strip_tags($text, $allowed);
832
            $text = $this->makeClickable($text);
833
        }
834
        if ($smiley == 1) {
835
            $text = $this->smiley($text);
836
        }
837
        if ($bbcode == 1) {
838
            $text =& $this->xoopsCodeDecode($text);
839
        }
840
        $text = $this->nl2Br($text);
841
842
        return $text;
843
    }
844
845
    /**
846
     * MyTextSanitizer::sanitizeForPreview()
847
     *
848
     * @param  mixed   $text
849
     * @param  integer $allowhtml
850
     * @param  integer $smiley
851
     * @param  mixed   $bbcode
852
     * @return mixed|string
853
     */
854
    public function sanitizeForPreview($text, $allowhtml = 0, $smiley = 1, $bbcode = 1)
855
    {
856
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
857
        $text = $this->oopsStripSlashesGPC($text);
858
        if ($allowhtml == 0) {
859
            $text = $this->htmlSpecialChars($text);
860
        } else {
861
            // $config =& $GLOBALS['xoopsConfig'];
862
            // $allowed = $config['allowed_html'];
863
            // $text = strip_tags($text, $allowed);
864
            $text = $this->makeClickable($text);
865
        }
866
        if ($smiley == 1) {
867
            $text = $this->smiley($text);
868
        }
869
        if ($bbcode == 1) {
870
            $text =& $this->xoopsCodeDecode($text);
871
        }
872
        $text = $this->nl2Br($text);
873
874
        return $text;
875
    }
876
877
    /**
878
     * MyTextSanitizer::makeTboxData4Save()
879
     *
880
     * @param  mixed $text
881
     * @return string
882
     */
883
    public function makeTboxData4Save($text)
884
    {
885
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
886
887
        // $text = $this->undoHtmlSpecialChars($text);
888
        return $this->addSlashes($text);
889
    }
890
891
    /**
892
     * MyTextSanitizer::makeTboxData4Show()
893
     *
894
     * @param  mixed $text
895
     * @param  mixed $smiley
896
     * @return mixed|string
897
     */
898
    public function makeTboxData4Show($text, $smiley = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $smiley is not used and could be removed. ( Ignorable by Annotation )

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

898
    public function makeTboxData4Show($text, /** @scrutinizer ignore-unused */ $smiley = 0)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
899
    {
900
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
901
        $text = $this->htmlSpecialChars($text);
902
903
        return $text;
904
    }
905
906
    /**
907
     * MyTextSanitizer::makeTboxData4Edit()
908
     *
909
     * @param  mixed $text
910
     * @return string
911
     */
912
    public function makeTboxData4Edit($text)
913
    {
914
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
915
916
        return $this->htmlSpecialChars($text);
917
    }
918
919
    /**
920
     * MyTextSanitizer::makeTboxData4Preview()
921
     *
922
     * @param  mixed $text
923
     * @param  mixed $smiley
924
     * @return mixed|string
925
     */
926
    public function makeTboxData4Preview($text, $smiley = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $smiley is not used and could be removed. ( Ignorable by Annotation )

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

926
    public function makeTboxData4Preview($text, /** @scrutinizer ignore-unused */ $smiley = 0)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
927
    {
928
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
929
        $text = $this->stripSlashesGPC($text);
930
        $text = $this->htmlSpecialChars($text);
931
932
        return $text;
933
    }
934
935
    /**
936
     * MyTextSanitizer::makeTboxData4PreviewInForm()
937
     *
938
     * @param  mixed $text
939
     * @return string
940
     */
941
    public function makeTboxData4PreviewInForm($text)
942
    {
943
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
944
        $text = $this->stripSlashesGPC($text);
945
946
        return $this->htmlSpecialChars($text);
947
    }
948
949
    /**
950
     * MyTextSanitizer::makeTareaData4Save()
951
     *
952
     * @param  mixed $text
953
     * @return string
954
     */
955
    public function makeTareaData4Save($text)
956
    {
957
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
958
959
        return $this->addSlashes($text);
960
    }
961
962
    /**
963
     * MyTextSanitizer::makeTareaData4Show()
964
     *
965
     * @param  mixed   $text
966
     * @param  integer $html
967
     * @param  integer $smiley
968
     * @param  mixed   $xcode
969
     * @return mixed|string
970
     */
971
    public function &makeTareaData4Show(&$text, $html = 1, $smiley = 1, $xcode = 1)
972
    {
973
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
974
        $text =& $this->displayTarea($text, $html, $smiley, $xcode);
975
976
        return $text;
977
    }
978
979
    /**
980
     * MyTextSanitizer::makeTareaData4Edit()
981
     *
982
     * @param  mixed $text
983
     * @return string
984
     */
985
    public function makeTareaData4Edit($text)
986
    {
987
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
988
989
        return $this->htmlSpecialChars($text);
990
    }
991
992
    /**
993
     * MyTextSanitizer::makeTareaData4Preview()
994
     *
995
     * @param  mixed   $text
996
     * @param  integer $html
997
     * @param  integer $smiley
998
     * @param  mixed   $xcode
999
     * @return mixed|string
1000
     */
1001
    public function &makeTareaData4Preview(&$text, $html = 1, $smiley = 1, $xcode = 1)
1002
    {
1003
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
1004
        $text =& $this->previewTarea($text, $html, $smiley, $xcode);
1005
1006
        return $text;
1007
    }
1008
1009
    /**
1010
     * MyTextSanitizer::makeTareaData4PreviewInForm()
1011
     *
1012
     * @param  mixed $text
1013
     * @return string
1014
     */
1015
    public function makeTareaData4PreviewInForm($text)
1016
    {
1017
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
1018
        // if magic_quotes_gpc is on, do stipslashes
1019
        $text = $this->stripSlashesGPC($text);
1020
1021
        return $this->htmlSpecialChars($text);
1022
    }
1023
1024
    /**
1025
     * MyTextSanitizer::makeTareaData4InsideQuotes()
1026
     *
1027
     * @param  mixed $text
1028
     * @return string
1029
     */
1030
    public function makeTareaData4InsideQuotes($text)
1031
    {
1032
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
1033
1034
        return $this->htmlSpecialChars($text);
1035
    }
1036
1037
    /**
1038
     * MyTextSanitizer::oopsStripSlashesGPC()
1039
     *
1040
     * @param  mixed $text
1041
     * @return string
1042
     */
1043
    public function oopsStripSlashesGPC($text)
1044
    {
1045
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
1046
1047
        return $this->stripSlashesGPC($text);
1048
    }
1049
1050
    /**
1051
     * MyTextSanitizer::oopsStripSlashesRT()
1052
     *
1053
     * @param  mixed $text
1054
     * @return mixed|string
1055
     */
1056
    public function oopsStripSlashesRT($text)
1057
    {
1058
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
1059
        if (get_magic_quotes_runtime()) {
1060
            $text = stripslashes($text);
1061
        }
1062
1063
        return $text;
1064
    }
1065
1066
    /**
1067
     * MyTextSanitizer::oopsAddSlashes()
1068
     *
1069
     * @param  mixed $text
1070
     * @return string
1071
     */
1072
    public function oopsAddSlashes($text)
1073
    {
1074
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
1075
1076
        return $this->addSlashes($text);
1077
    }
1078
1079
    /**
1080
     * MyTextSanitizer::oopsHtmlSpecialChars()
1081
     *
1082
     * @param  mixed $text
1083
     * @return string
1084
     */
1085
    public function oopsHtmlSpecialChars($text)
1086
    {
1087
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
1088
1089
        return $this->htmlSpecialChars($text);
1090
    }
1091
1092
    /**
1093
     * MyTextSanitizer::oopsNl2Br()
1094
     *
1095
     * @param  mixed $text
1096
     * @return string
1097
     */
1098
    public function oopsNl2Br($text)
1099
    {
1100
        $GLOBALS['xoopsLogger']->addDeprecated(__CLASS__ . '::' . __FUNCTION__ . ' is deprecated');
1101
1102
        return $this->nl2Br($text);
1103
    }
1104
}
1105