MyTextSanitizer::oopsAddSlashes()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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-2025 XOOPS Project (https://xoops.org)
13
 * @license             GNU GPL 2 (https://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-2025 XOOPS Project (https://xoops.org)
26
 */
27
class MyTextSanitizerExtension
28
{
29
    public $instance;
30
    public $myts;
31
    public $config;
32
    public $image_path;
33
34
    /**
35
     * Constructor
36
     *
37
     * @param MyTextSanitizer $myts
38
     */
39
    public function __construct(MyTextSanitizer $myts)
40
    {
41
        $this->myts         = $myts;
42
        $this->image_path = XOOPS_URL . '/images/form';
43
    }
44
45
    /**
46
     * loadConfig
47
     *
48
     * @param  string $path
49
     * @return string|array
50
     */
51
    public static function loadConfig($path = null)
52
    {
53
        $myts   = \MyTextSanitizer::getInstance();
54
        $extensionName = (null === $path) ? '' : basename($path);
55
        $pathDist = $myts->path_basic;
56
        $pathConfig = $myts->path_config;
57
58
        if ('' !== $extensionName) {
59
            $configFileName = $pathConfig . '/config.' . $extensionName . '.php';
60
            $distFileName = $pathDist . '/' . $extensionName . '/config.' . $extensionName . '.dist.php';
61
        } else {
62
            $configFileName = $pathConfig . '/config.php';
63
            $distFileName = $pathDist . '/config.dist.php';
64
        }
65
        if (!file_exists($configFileName)) {
66
            if (false === copy($distFileName, $configFileName)) {
67
                trigger_error('Could not create textsanitizer config file ' . basename($configFileName));
68
                return $a = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $a is dead and can be removed.
Loading history...
69
            }
70
        }
71
        $configs = include $configFileName;
72
        return $configs;
73
    }
74
75
    /**
76
     * Merge Config
77
     *
78
     * @param  array $config_default
79
     * @param  array $config_custom
80
     * @return array
81
     */
82
    public static function mergeConfig($config_default, $config_custom)
83
    {
84
        if (is_array($config_custom)) {
0 ignored issues
show
introduced by
The condition is_array($config_custom) is always true.
Loading history...
85
            foreach ($config_custom as $key => $val) {
86
                if (is_array($config_default[$key])) {
87
                    $config_default[$key] = self::mergeConfig($config_default[$key], $config_custom[$key]);
88
                } else {
89
                    $config_default[$key] = $val;
90
                }
91
            }
92
        }
93
94
        return $config_default;
95
    }
96
97
    /**
98
     * encode
99
     *
100
     * @param string $textarea_id id attribute of text area
101
     *
102
     * @return array
103
     */
104
    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

104
    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...
105
    {
106
        return [[], []];
107
    }
108
109
    /**
110
     * decode
111
     *
112
     * @param string $url
113
     * @param string|integer $width
114
     * @param string|integer $height
115
     *
116
     * @return Null
117
     */
118
    public static function decode($url, $width, $height)
0 ignored issues
show
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

118
    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...
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

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

259
                while (false !== ($smiles = $xoopsDB->fetchArray(/** @scrutinizer ignore-type */ $result))) {
Loading history...
260
                    $this->smileys[] = $smiles;
261
                }
262
            }
263
        }
264
        if ($isAll) {
265
            return $this->smileys;
266
        }
267
268
        $smileys = [];
269
        foreach ($this->smileys as $smile) {
270
            if (empty($smile['display'])) {
271
                continue;
272
            }
273
            $smileys[] = $smile;
274
        }
275
276
        return $smileys;
277
    }
278
279
    /**
280
     * Replace emoticons in the message with smiley images
281
     *
282
     * @param  string $message
283
     * @return string
284
     */
285
    public function smiley($message)
286
    {
287
        $smileys = $this->getSmileys();
288
        foreach ($smileys as $smile) {
289
            $message = str_replace($smile['code'], '<img class="imgsmile" src="' . XOOPS_UPLOAD_URL . '/' . htmlspecialchars($smile['smile_url'], ENT_QUOTES | ENT_HTML5) . '" alt="" />', $message);
290
        }
291
292
        return $message;
293
    }
294
295
    /**
296
     * Callback to process email address match
297
     *
298
     * @param array $match array of matched elements
299
     *
300
     * @return string
301
     */
302
    protected function makeClickableCallbackEmailAddress0($match)
303
    {
304
        $email = $match[2];  // Extract the email address
305
        return $match[1] . '<a href="mailto:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '</a>';
306
    }
307
308
    /**
309
     * Make links in the text clickable
310
     * Presently handles email addresses and http, https, ftp, and sftp urls
311
     * (Note: at this time, major browsers no longer directly handle ftp/sftp urls.)
312
     *
313
     * @param string $text
314
     * @return string
315
     */
316
    public function makeClickable0($text)
317
    {
318
        // Decode HTML entities to ensure URLs are properly formatted
319
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
320
321
        // Convert email addresses into clickable mailto links
322
        $pattern = "/(^|[\s\n]|<br\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";
323
        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);
324
325
        // Convert URLs into clickable links
326
        $pattern = "/(?:\s|^|[\(\[\{>])((https?:\/\/|s?ftp:\/\/|www\.)[^\s<>\(\)\[\]]+[^\s<>\(\)\[\]\.,!\"'\(\)\[\]{}<>])(?<![\.,!\"'\(\)\[\]{}])/";
327
        $text = preg_replace_callback(
328
            $pattern,
329
            function ($matches) {
330
                $url = $matches[1];
331
                $prefix = $matches[0][0] ?? ''; // Get the prefix character (space, bracket, etc.)
332
                if (strpos($url, 'www.') === 0) {
333
                    $url = "http://" . $url;
334
                }
335
                $relAttr = strpos($url, 'ftp://') === 0 || strpos($url, 'sftp://') === 0 ? 'external' : 'external noopener nofollow';
336
                return $prefix . '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="' . $relAttr . '">' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '</a>';
337
            },
338
            $text
339
        );
340
341
        // Convert URLs within angular brackets into clickable links
342
        $pattern = "/(<)(https?:\/\/[^\s>]+)(>)/i";
343
        $text = preg_replace_callback(
344
            $pattern,
345
            function ($matches) {
346
                $url = htmlspecialchars($matches[2], ENT_QUOTES, 'UTF-8');
347
                return $matches[1] . '<a href="' . $url . '" target="_blank" rel="external noopener nofollow">' . $url . '</a>' . $matches[3];
348
            },
349
            $text
350
        );
351
352
        // Ensure consistent handling of newlines by converting them to <br /> tags
353
        $text = nl2br($text);
354
355
        // Clean up extra newlines
356
        $text = preg_replace('/(<br \/>|<br>)[\n\s]*/', '$1', $text);
357
358
        return $text;
359
    }
360
361
362
    protected function makeClickableCallbackEmailAddress1($match)
363
    {
364
        $email = $match[2];  // Extract the email address
365
        return $match[1] . '<a href="mailto:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '</a>';
366
    }
367
368
    public function makeClickable1($text)
369
    {
370
        // Decode HTML entities to ensure URLs are properly formatted
371
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
372
373
        // Convert email addresses into clickable mailto links
374
        $pattern = "/(^|[\s\n]|<br\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";
375
        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);
376
377
        // Convert URLs into clickable links
378
        $pattern = "/(?:\s|^|[\(\[\{>])((https?:\/\/|s?ftp:\/\/|www\.)[^\s<>\(\)\[\]]+[^\s<>\(\)\[\]\.,!\"'\(\)\[\]{}<>])(?<![\.,!\"'\(\)\[\]{}])/";
379
        $text = preg_replace_callback(
380
            $pattern,
381
            function ($matches) {
382
                $url = $matches[1];
383
                $prefix = $matches[0][0] ?? ''; // Get the prefix character (space, bracket, etc.)
384
                if (strpos($url, 'www.') === 0) {
385
                    $url = "http://" . $url;
386
                }
387
                $relAttr = strpos($url, 'ftp://') === 0 || strpos($url, 'sftp://') === 0 ? 'external' : 'external noopener nofollow';
388
                return $prefix . '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="' . $relAttr . '">' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '</a>';
389
            },
390
            $text
391
        );
392
393
        // Convert URLs within angular brackets into clickable links
394
        $pattern = "/(<)(https?:\/\/[^\s>]+)(>)/i";
395
        $text = preg_replace_callback(
396
            $pattern,
397
            function ($matches) {
398
                $url = htmlspecialchars($matches[2], ENT_QUOTES, 'UTF-8');
399
                return $matches[1] . '<a href="' . $url . '" target="_blank" rel="external noopener nofollow">' . $url . '</a>' . $matches[3];
400
            },
401
            $text
402
        );
403
404
        $text = preg_replace('/[\n\s]+/', ' ', $text);
405
406
        return $text;
407
    }
408
409
    protected function makeClickableCallbackEmailAddress2($match)
410
    {
411
        $email = $match[2];  // Extract the email address
412
        return $match[1] . '<a href="mailto:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '</a>';
413
    }
414
415
    public function makeClickable2($text)
416
    {
417
        // Decode HTML entities to ensure URLs are properly formatted
418
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
419
420
        // Convert email addresses into clickable mailto links
421
/*        $pattern = "/(^|[\s\n]|<br\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";*/
422
//        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);
423
424
425
        $pattern = "/(^|[\s\n]|<br\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";
426
        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);
427
428
        // Convert URLs into clickable links
429
        $pattern = "/(?:\s|^|[\(\[\{>])((https?:\/\/|s?ftp:\/\/|www\.)[^\s<>\(\)\[\]]+[^\s<>\(\)\[\]\.,!\"'\(\)\[\]{}<>])(?<![\.,!\"'\(\)\[\]{}])/";
430
        $text = preg_replace_callback(
431
            $pattern,
432
            function ($matches) {
433
                $url = $matches[1];
434
                $prefix = $matches[0][0] ?? ''; // Get the prefix character (space, bracket, etc.)
435
                if (strpos($url, 'www.') === 0) {
436
                    $url = "http://" . $url;
437
                }
438
                $relAttr = strpos($url, 'ftp://') === 0 || strpos($url, 'sftp://') === 0 ? 'external' : 'external noopener nofollow';
439
                return $prefix . '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="' . $relAttr . '">' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '</a>';
440
            },
441
            $text
442
        );
443
444
        // Convert URLs within angular brackets into clickable links
445
        $pattern = "/(<)(https?:\/\/[^\s>]+)(>)/i";
446
        $text = preg_replace_callback(
447
            $pattern,
448
            function ($matches) {
449
                $url = htmlspecialchars($matches[2], ENT_QUOTES, 'UTF-8');
450
                return $matches[1] . '<a href="' . $url . '" target="_blank" rel="external noopener nofollow">' . $url . '</a>' . $matches[3];
451
            },
452
            $text
453
        );
454
455
        return $text;
456
    }
457
458
459
    protected function makeClickableCallbackEmailAddress3($match)
460
    {
461
        $email = $match[2];  // Extract the email address
462
        return $match[1] . '<a href="mailto:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '</a>';
463
    }
464
465
    /**
466
     * Make links in the text clickable
467
     * Presently handles email addresses and http, https, ftp, and sftp urls
468
     * (Note: at this time, major browsers no longer directly handle ftp/sftp urls.)
469
     *
470
     * @param string $text
471
     * @return string
472
     */
473
    public function makeClickable3($text)
474
    {
475
        // Decode HTML entities to ensure URLs are properly formatted
476
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
477
478
        // Convert email addresses into clickable mailto links
479
        $pattern = "/(^|[\s\n]|<br\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";
480
        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);
481
482
        // Convert URLs into clickable links
483
        $pattern = "/(?:\s|^|[\(\[\{>])((https?:\/\/|s?ftp:\/\/|www\.)[^\s<>\(\)\[\]]+[^\s<>\(\)\[\]\.,!\"'\(\)\[\]{}<>])(?<![\.,!\"'\(\)\[\]{}])/";
484
        $text = preg_replace_callback(
485
            $pattern,
486
            function ($matches) {
487
                $url = $matches[1];
488
                $prefix = $matches[0][0] ?? ''; // Get the prefix character (space, bracket, etc.)
489
                if (strpos($url, 'www.') === 0) {
490
                    $url = "http://" . $url;
491
                }
492
                $relAttr = strpos($url, 'ftp://') === 0 || strpos($url, 'sftp://') === 0 ? 'external' : 'external noopener nofollow';
493
                return $prefix . '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="' . $relAttr . '">' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '</a>';
494
            },
495
            $text
496
        );
497
498
        // Ensure consistent handling of newlines by converting them to <br /> tags
499
//        $text = nl2br($text);
500
501
        $text = preg_replace('/[\n\s]+/', ' ', $text);
502
503
        return $text;
504
    }
505
506
507
508
    protected function makeClickableCallbackEmailAddress4($match)
509
    {
510
        $email = $match[2];  // Extract the email address
511
        return $match[1] . '<a href="mailto:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '</a>';
512
    }
513
514
    /**
515
     * Make links in the text clickable
516
     * Presently handles email addresses and http, https, ftp, and sftp urls
517
     * (Note: at this time, major browsers no longer directly handle ftp/sftp urls.)
518
     *
519
     * @param string $text
520
     * @return string
521
     */
522
    public function makeClickable4($text)
523
    {
524
        // Decode HTML entities to ensure URLs are properly formatted
525
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
526
527
        // Convert email addresses into clickable mailto links
528
        $pattern = "/(^|[\s\n]|<br\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";
529
        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);
530
531
        // Convert URLs into clickable links
532
        $pattern = "/(?:\s|^|[\(\[\{>])((https?:\/\/|s?ftp:\/\/|www\.)[^\s<>\(\)\[\]]+[^\s<>\(\)\[\]\.,!\"'\(\)\[\]{}<>])(?<![\.,!\"'\(\)\[\]{}])/";
533
        $text = preg_replace_callback(
534
            $pattern,
535
            function ($matches) {
536
                $url = $matches[1];
537
                $prefix = $matches[0][0] ?? ''; // Get the prefix character (space, bracket, etc.)
538
                if (strpos($url, 'www.') === 0) {
539
                    $url = "http://" . $url;
540
                }
541
                $relAttr = strpos($url, 'ftp://') === 0 || strpos($url, 'sftp://') === 0 ? 'external' : 'external noopener nofollow';
542
                return $prefix . '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="' . $relAttr . '">' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '</a>';
543
            },
544
            $text
545
        );
546
547
        // Convert line breaks to <br> tags
548
//        $text = str_replace("\n", "<br>", $text);
549
        $text = preg_replace('/[\n\s]+/', ' ', $text);
550
551
        return $text;
552
    }
553
554
    /**
555
     * Callback to process email address match
556
     *
557
     * @param array $match array of matched elements
558
     *
559
     * @return string
560
     */
561
    protected function makeClickableCallbackEmailAddress($match)
562
    {
563
        $email = $match[2];  // Extract the email address
564
        return $match[1] . '<a href="mailto:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '</a>';
565
    }
566
567
    /**
568
     * Make links in the text clickable
569
     * Presently handles email addresses and http, https, ftp, and sftp urls
570
     * (Note: at this time, major browsers no longer directly handle ftp/sftp urls.)
571
     *
572
     * @param string $text
573
     * @return string
574
     */
575
    public function makeClickable6($text)
576
    {
577
        // Decode HTML entities to ensure URLs are properly formatted
578
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
579
580
        // Convert line breaks and multiple spaces to a single space
581
        $text = preg_replace('/[\n\s]+/', ' ', $text);
582
583
        // Convert email addresses into clickable mailto links
584
        $pattern = "/(^|[\s\n]|<br\s*\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";
585
        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);
586
587
        // Convert URLs into clickable links, allowing for angle brackets
588
        $pattern = "/(?:\s|^|[\(\[\{>])(<)?((https?:\/\/|s?ftp:\/\/|www\.)[^\s<>\(\)\[\]]+[^\s<>\(\)\[\]\.,!\"'\(\)\[\]{}<>])(?<![\.,!\"'\(\)\[\]{}])/";
589
        $text = preg_replace_callback(
590
            $pattern,
591
            function ($matches) {
592
                $url = $matches[2];
593
                $prefix = $matches[0][0] ?? ''; // Get the prefix character (space, bracket, etc.)
594
                $openingBracket = $matches[1] ?? ''; // Check for the opening angle bracket
595
596
                if (strpos($url, 'www.') === 0) {
597
                    $url = "http://" . $url;
598
                }
599
                $relAttr = strpos($url, 'ftp://') === 0 || strpos($url, 'sftp://') === 0 ? 'external' : 'external noopener nofollow';
600
601
                // Add the opening bracket back if it was present
602
                return $prefix . $openingBracket . '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="' . $relAttr . '">' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '</a>';
603
            },
604
            $text
605
        );
606
607
        return $text;
608
    }
609
610
    public function makeClickable7($text)
611
    {
612
        // Decode HTML entities to ensure URLs are properly formatted
613
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
614
615
        // Convert line breaks and multiple spaces to a single space
616
        $text = preg_replace('/[\n\s]+/', ' ', $text);
617
618
        // Convert email addresses into clickable mailto links
619
        $pattern = "/(^|[\s\n]|<br\s*\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";
620
        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);
621
622
        // Convert URLs into clickable links, allowing for angle brackets, file paths, and custom protocols
623
        $pattern = "/(?:\s|^|[\(\[\{>])(<)?((https?:\/\/|s?ftp:\/\/|file:\/\/|custom:\/\/|www\.)[^\s<>\(\)\[\]]+[^\s<>\(\)\[\]\.,!\"'\(\)\[\]{}<>])(?<![\.,!\"'\(\)\[\]{}])/";
624
        $text = preg_replace_callback(
625
            $pattern,
626
            function ($matches) {
627
                $url = $matches[2];
628
                $prefix = $matches[0][0] ?? ''; // Get the prefix character (space, bracket, etc.)
629
                $openingBracket = $matches[1] ?? ''; // Check for the opening angle bracket
630
631
                if (strpos($url, 'www.') === 0) {
632
                    $url = "http://" . $url;
633
                }
634
                $relAttr = (strpos($url, 'ftp://') === 0 || strpos($url, 'sftp://') === 0 || strpos($url, 'file://') === 0 || strpos($url, 'custom://') === 0) ? 'external' : 'external noopener nofollow';
635
636
                // Add the opening bracket back if it was present
637
                return $prefix . $openingBracket . '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="' . $relAttr . '">' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '</a>';
638
            },
639
            $text
640
        );
641
642
        return $text;
643
    }
644
645
    public function makeClickable($text) {
646
        // Decode HTML entities
647
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
648
649
        // Convert line breaks and multiple spaces to a single space
650
        $text = preg_replace('/[\n\s]+/', ' ', $text);
651
652
        // Convert email addresses into clickable mailto links
653
        $pattern = "/(^|[\s\n]|<br\s*\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";
654
        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);
655
656
        // Convert URLs into clickable links, allowing for angle brackets, file paths, and custom protocols
657
        $pattern = "/(?:\s|^|[\(\[\{>])(<)?((https?:\/\/|s?ftp:\/\/|file:\/\/|custom:\/\/|www\.)[^\s<>\(\)\[\]]+[^\s<>\(\)\[\]\.,!\"'\(\)\[\]{}<>])(?<![\.,!\"'\(\)\[\]{}])/";
658
        $text = preg_replace_callback(
659
            $pattern,
660
            function ($matches) {
661
                $url = $matches[2];
662
                $prefix = $matches[0][0] ?? ''; // Get the prefix character (space, bracket, etc.)
663
                $openingBracket = $matches[1] ?? ''; // Check for the opening angle bracket
664
665
                // Ensure the URL is not a javascript: URL
666
                if (stripos($url, 'javascript:') === 0) {
667
                    return $matches[0];
668
                }
669
670
                // Add http prefix if missing
671
                if (strpos($url, 'www.') === 0) {
672
                    $url = "http://" . $url;
673
                }
674
675
                // Allow only specific protocols
676
                $allowedProtocols = ['http://', 'https://', 'ftp://', 'sftp://', 'file://', 'custom://'];
677
                $protocolAllowed = false;
678
                foreach ($allowedProtocols as $protocol) {
679
                    if (strpos($url, $protocol) === 0) {
680
                        $protocolAllowed = true;
681
                        break;
682
                    }
683
                }
684
                if (!$protocolAllowed) {
685
                    return $matches[0];
686
                }
687
688
                // Check if the URL is already inside an anchor tag, specifically looking for href attribute
689
                if (!preg_match('#<a\s[^>]*href\s*=\s*(["\'])' . preg_quote($url, '/') . '\\1[^>]*>#i', $url)) { // <-- Change here!
690
                    $relAttr = (strpos($url, 'ftp://') === 0 || strpos($url, 'sftp://') === 0 || strpos($url, 'file://') === 0 || strpos($url, 'custom://') === 0) ? 'external' : 'external noopener nofollow';
691
                    return $prefix . $openingBracket . '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="' . $relAttr . '">' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '</a>';
692
                }
693
694
                return $matches[0]; // Return the original match if it's already an anchor tag
695
            },
696
            $text
697
        );
698
699
        return $text;
700
    }
701
702
    /**
703
     * MyTextSanitizer::truncate()
704
     *
705
     * @param  mixed $text
706
     * @return mixed|string
707
     */
708
    public function truncate($text)
709
    {
710
        $instance = \MyTextSanitizer::getInstance();
711
        if (empty($text) || empty($instance->config['truncate_length']) || strlen($text) < $instance->config['truncate_length']) {
712
            return $text;
713
        }
714
        $len = floor($instance->config['truncate_length'] / 2);
715
        $ret = substr($text, 0, $len) . ' ... ' . substr($text, 5 - $len);
0 ignored issues
show
Bug introduced by
$len of type double is incompatible with the type integer|null 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

715
        $ret = substr($text, 0, /** @scrutinizer ignore-type */ $len) . ' ... ' . substr($text, 5 - $len);
Loading history...
Bug introduced by
5 - $len of type double is incompatible with the type integer expected by parameter $offset 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

715
        $ret = substr($text, 0, $len) . ' ... ' . substr($text, /** @scrutinizer ignore-type */ 5 - $len);
Loading history...
716
717
        return $ret;
718
    }
719
720
    /**
721
     * Replace XoopsCodes with their equivalent HTML formatting
722
     *
723
     * @param  string   $text
724
     * @param  bool|int $allowimage Allow images in the text?
725
     *                              On FALSE, uses links to the images.
726
     * @return string
727
     */
728
    public function &xoopsCodeDecode(&$text, $allowimage = 1)
729
    {
730
        $patterns       = [];
731
        $replacements   = [];
732
        $patterns[]     = "/\[siteurl=(['\"]?)([^\"'<>]*)\\1](.*)\[\/siteurl\]/sU";
733
        $replacements[] = '<a href="' . XOOPS_URL . '/\\2" title="">\\3</a>';
734
        $patterns[]     = "/\[url=(['\"]?)(http[s]?:\/\/[^\"'<>]*)\\1](.*)\[\/url\]/sU";
735
        $replacements[] = '<a href="\\2" rel="noopener external" title="">\\3</a>';
736
        $patterns[]     = "/\[url=(['\"]?)(ftp?:\/\/[^\"'<>]*)\\1](.*)\[\/url\]/sU";
737
        $replacements[] = '<a href="\\2" rel="external" title="">\\3</a>';
738
        $patterns[]     = "/\[url=(['\"]?)([^'\"<>]*)\\1](.*)\[\/url\]/sU";
739
        $replacements[] = '<a href="http://\\2" rel="noopener external" title="">\\3</a>';
740
        $patterns[]     = "/\[color=(['\"]?)([a-zA-Z0-9#]+)\\1?](.*)\[\/color\]/sU";
741
        $replacements[] = '<span style="color: #\\2;">\\3</span>';
742
        $patterns[]     = "/\[size=(['\"]?)([a-zA-Z0-9-]+)\\1?](.*)\[\/size\]/sU";
743
        $replacements[] = '<span style="font-size: \\2;">\\3</span>';
744
        $patterns[]     = "/\[font=(['\"]?)([^;<>\*\(\)\"']*)\\1](.*)\[\/font\]/sU";
745
        $replacements[] = '<span style="font-family: \\2;">\\3</span>';
746
        $patterns[]     = "/\[email]([^;<>\*\(\)\"']*)\[\/email\]/sU";
747
        $replacements[] = '<a href="mailto:\\1" title="">\\1</a>';
748
749
        $patterns[]     = '/\[b](.*)\[\/b\]/sU';
750
        $replacements[] = '<strong>\\1</strong>';
751
        $patterns[]     = '/\[i](.*)\[\/i\]/sU';
752
        $replacements[] = '<em>\\1</em>';
753
        $patterns[]     = '/\[u](.*)\[\/u\]/sU';
754
        $replacements[] = '<span style="text-decoration: underline;">\\1</span>';
755
        $patterns[]     = '/\[d](.*)\[\/d\]/sU';
756
        $replacements[] = '<del>\\1</del>';
757
        $patterns[]     = '/\[center](.*)\[\/center\]/sU';
758
        $replacements[] = '<div style="text-align: center;">\\1</div>';
759
        $patterns[]     = '/\[left](.*)\[\/left\]/sU';
760
        $replacements[] = '<div style="text-align: left;">\\1</div>';
761
        $patterns[]     = '/\[right](.*)\[\/right\]/sU';
762
        $replacements[] = '<div style="text-align: right;">\\1</div>';
763
764
        $this->text         = $text;
765
        $this->patterns     = $patterns;
766
        $this->replacements = $replacements;
767
768
        $this->config['allowimage'] = $allowimage;
769
        $this->executeExtensions();
770
771
        $text = preg_replace($this->patterns, $this->replacements, $this->text);
772
        //-------------------------------------------------------------------------------
773
        $count = count($this->callbackPatterns);
774
775
        for ($i = 0; $i < $count; ++$i) {
776
            $text = preg_replace_callback($this->callbackPatterns[$i], $this->callbacks[$i], $text);
777
        }
778
        //------------------------------------------------------------------------------
779
        $text = $this->quoteConv($text);
780
781
        return $text;
782
    }
783
784
    /**
785
     * Convert quote tags
786
     *
787
     * @param  string $text
788
     * @return string
789
     */
790
    public function quoteConv($text)
791
    {
792
        //look for both open and closing tags in the correct order
793
        $pattern     = '/\[quote](.*)\[\/quote\]/sU';
794
        $replacement = _QUOTEC . '<div class="xoopsQuote"><blockquote>\\1</blockquote></div>';
795
796
        $text = preg_replace($pattern, $replacement, $text, -1, $count);
797
        //no more matches, return now
798
        if (!$count) {
799
            return $text;
800
        }
801
802
        //new matches could have been created, keep doing it until we have no matches
803
        return $this->quoteConv($text);
804
    }
805
806
    /**
807
     * A quick solution for filtering XSS scripts
808
     *
809
     * @TODO : To be improved
810
     * @param $text
811
     * @return mixed
812
     */
813
    public function filterXss($text)
814
    {
815
        $patterns       = [];
816
        $replacements   = [];
817
        $text           = str_replace("\x00", '', $text);
818
        $c              = "[\x01-\x1f]*";
819
        $patterns[]     = "/\bj{$c}a{$c}v{$c}a{$c}s{$c}c{$c}r{$c}i{$c}p{$c}t{$c}[\s]*:/si";
820
        $replacements[] = 'javascript;';
821
        $patterns[]     = "/\ba{$c}b{$c}o{$c}u{$c}t{$c}[\s]*:/si";
822
        $replacements[] = 'about;';
823
        $patterns[]     = "/\bx{$c}s{$c}s{$c}[\s]*:/si";
824
        $replacements[] = 'xss;';
825
        $text           = preg_replace($patterns, $replacements, $text);
826
827
        return $text;
828
    }
829
830
    /**
831
     * Convert linebreaks to <br> tags
832
     *
833
     * @param  string $text
834
     * @return string
835
     */
836
    public function nl2Br($text)
837
    {
838
        return preg_replace('/(\015\012)|(\015)|(\012)/', '<br>', $text);
839
    }
840
841
    /**
842
     * Add slashes to the text if magic_quotes_gpc is turned off.
843
     *
844
     * @param  string $text
845
     * @return string
846
     */
847
    public function addSlashes($text)
848
    {
849
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
850
        return $text;
851
    }
852
853
    /**
854
     * Convert special characters to HTML entities
855
     *
856
     * @param  string $text    string being converted
857
     * @param  int|null    $quote_style
858
     * @param  string|null $charset character set used in conversion
859
     * @param  bool   $double_encode
860
     * @return string
861
     */
862
    public function htmlSpecialChars(string $text, ?int $quote_style = null, ?string $charset = null, $double_encode = true)
863
    {
864
        if ($quote_style === null) {
865
            $quote_style = ENT_QUOTES;
866
        }
867
        $text = (string) $text;
868
        if (version_compare(phpversion(), '5.2.3', '>=')) {
869
            $text = htmlspecialchars($text, $quote_style, $charset ?: (defined('_CHARSET') ? _CHARSET : 'UTF-8'), $double_encode);
870
        } else {
871
            $text = htmlspecialchars($text, $quote_style);
872
        }
873
874
        return preg_replace(['/&amp;/i', '/&nbsp;/i'], ['&', '&amp;nbsp;'], $text);
875
    }
876
877
    /**
878
     * Reverses {@link htmlSpecialChars()}
879
     *
880
     * @param  string $text
881
     * @return string
882
     */
883
    public function undoHtmlSpecialChars($text)
884
    {
885
        return preg_replace(['/&gt;/i', '/&lt;/i', '/&quot;/i', '/&#039;/i', '/&amp;nbsp;/i'], ['>', '<', '"', '\'', '&nbsp;'], $text);
886
    }
887
888
    /**
889
     * Filters textarea form data in DB for display
890
     *
891
     * @param  string   $text
892
     * @param  bool|int $html   allow html?
893
     * @param  bool|int $smiley allow smileys?
894
     * @param  bool|int $xcode  allow xoopscode?
895
     * @param  bool|int $image  allow inline images?
896
     * @param  bool|int $br     convert linebreaks?
897
     * @return string
898
     */
899
    public function &displayTarea($text, $html = 0, $smiley = 1, $xcode = 1, $image = 1, $br = 1)
900
    {
901
        $text = (string) $text;
902
        $charset = (defined('_CHARSET') ? _CHARSET : 'UTF-8');
903
        if (function_exists('mb_convert_encoding')) {
904
            $text = mb_convert_encoding($text, $charset, mb_detect_encoding($text, mb_detect_order(), true));
0 ignored issues
show
Bug introduced by
It seems like mb_detect_order() can also be of type true; however, parameter $encodings of mb_detect_encoding() does only seem to accept array|null|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

904
            $text = mb_convert_encoding($text, $charset, mb_detect_encoding($text, /** @scrutinizer ignore-type */ mb_detect_order(), true));
Loading history...
905
        }
906
        if ($html && $br) {
907
            $testText = strip_tags($text);
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type array; however, parameter $string of strip_tags() 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

907
            $testText = strip_tags(/** @scrutinizer ignore-type */ $text);
Loading history...
908
            if (mb_strlen($text) != mb_strlen($testText)) {
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type array; however, parameter $string of mb_strlen() 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

908
            if (mb_strlen(/** @scrutinizer ignore-type */ $text) != mb_strlen($testText)) {
Loading history...
909
                $br = 0;
910
            }
911
            unset($testText);
912
        }
913
        if ($html != 1) {
914
            // html not allowed
915
            $text = $this->htmlSpecialChars($text, ENT_COMPAT, $charset);
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type array; however, parameter $text of MyTextSanitizer::htmlSpecialChars() 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

915
            $text = $this->htmlSpecialChars(/** @scrutinizer ignore-type */ $text, ENT_COMPAT, $charset);
Loading history...
916
        }
917
        $text = $this->codePreConv($text, $xcode); // Ryuji_edit(2003-11-18)
918
        if ($smiley != 0) {
919
            // process smiley
920
            $text = $this->smiley($text);
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type array; however, parameter $message of MyTextSanitizer::smiley() 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

920
            $text = $this->smiley(/** @scrutinizer ignore-type */ $text);
Loading history...
921
        }
922
        if ($xcode != 0) {
923
            // decode xcode
924
            if ($image != 0) {
925
                // image allowed
926
                $text = & $this->xoopsCodeDecode($text);
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type array; however, parameter $text of MyTextSanitizer::xoopsCodeDecode() 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

926
                $text = & $this->xoopsCodeDecode(/** @scrutinizer ignore-type */ $text);
Loading history...
927
            } else {
928
                // image not allowed
929
                $text = & $this->xoopsCodeDecode($text, 0);
930
            }
931
        }
932
        if ($br != 0) {
933
            $text = $this->nl2Br($text);
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type array; however, parameter $text of MyTextSanitizer::nl2Br() 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

933
            $text = $this->nl2Br(/** @scrutinizer ignore-type */ $text);
Loading history...
934
        }
935
        $text = $this->codeConv($text, $xcode);
936
        $text = $this->makeClickable($text);
937
        if (!empty($this->config['filterxss_on_display'])) {
938
            $text = $this->filterXss($text);
939
        }
940
941
        return $text;
942
    }
943
944
    /**
945
     * Filters textarea form data submitted for preview
946
     *
947
     * @param  string   $text
948
     * @param  bool|int $html   allow html?
949
     * @param  bool|int $smiley allow smileys?
950
     * @param  bool|int $xcode  allow xoopscode?
951
     * @param  bool|int $image  allow inline images?
952
     * @param  bool|int $br     convert linebreaks?
953
     * @return string
954
     */
955
    public function &previewTarea($text, $html = 0, $smiley = 1, $xcode = 1, $image = 1, $br = 1)
956
    {
957
        $text = & $this->displayTarea($text, $html, $smiley, $xcode, $image, $br);
958
959
        return $text;
960
    }
961
962
    /**
963
     * Replaces banned words in a string with their replacements
964
     *
965
     * @param  string $text
966
     * @return string
967
     */
968
    public function &censorString(&$text)
969
    {
970
        $ret = $this->executeExtension('censor', $text);
971
        if ($ret === false) {
972
            return $text;
973
        }
974
975
        return $ret;
976
    }
977
978
    /**
979
     * MyTextSanitizer::codePreConv()
980
     *
981
     * @param  mixed $text
982
     * @param  mixed $xcode
983
     * @return mixed
984
     */
985
    public function codePreConv($text, $xcode = 1)
986
    {
987
        if ($xcode != 0) {
988
            //            $patterns = "/\[code([^\]]*?)\](.*)\[\/code\]/esU";
989
            //            $replacements = "'[code\\1]'.base64_encode('\\2').'[/code]'";
990
991
            $patterns = '/\[code([^\]]*?)\](.*)\[\/code\]/sU';
992
            $text = preg_replace_callback(
993
                $patterns,
994
                fn($matches) => '[code'. $matches[1] . ']' . base64_encode($matches[2]) . '[/code]',
995
                $text,
996
            );
997
        }
998
999
        return $text;
1000
    }
1001
1002
    /**
1003
     * @param $match
1004
     *
1005
     * @return string
1006
     */
1007
    public function codeConvCallback($match)
1008
    {
1009
        return '<div class="xoopsCode">' . $this->executeExtension('syntaxhighlight', str_replace('\\\"', '\"', base64_decode($match[2])), $match[1]) . '</div>';
1010
    }
1011
1012
    /**
1013
     * MyTextSanitizer::codeConv()
1014
     *
1015
     * @param  mixed $text
1016
     * @param  mixed $xcode
1017
     * @return mixed
1018
     */
1019
    public function codeConv($text, $xcode = 1)
1020
    {
1021
        if (empty($xcode)) {
1022
            return $text;
1023
        }
1024
        $patterns = '/\[code([^\]]*?)\](.*)\[\/code\]/sU';
1025
        $text1    = preg_replace_callback($patterns, [$this, 'codeConvCallback'], $text);
1026
1027
        return $text1;
1028
    }
1029
1030
    /**
1031
     * MyTextSanitizer::executeExtensions()
1032
     *
1033
     * @return bool
1034
     */
1035
    public function executeExtensions()
1036
    {
1037
        $extensions = array_filter($this->config['extensions']);
1038
        if (empty($extensions)) {
1039
            return true;
1040
        }
1041
        foreach (array_keys($extensions) as $extension) {
1042
            $this->executeExtension($extension);
1043
        }
1044
        return null;
1045
    }
1046
1047
    /**
1048
     * MyTextSanitizer::loadExtension()
1049
     *
1050
     * @param  mixed $name
1051
     * @return MyTextSanitizerExtension|false
1052
     */
1053
    public function loadExtension($name)
1054
    {
1055
        if (file_exists($file = $this->path_basic . '/' . $name . '/' . $name . '.php')) {
1056
            include_once $file;
1057
        } elseif (file_exists($file = $this->path_plugin . '/' . $name . '/' . $name . '.php')) {
1058
            include_once $file;
1059
        } else {
1060
            return false;
1061
        }
1062
        $class = 'Myts' . ucfirst($name);
1063
        if (!class_exists($class)) {
1064
            trigger_error("Extension '{$name}' does not exist", E_USER_WARNING);
1065
1066
            return false;
1067
        }
1068
        return new $class($this);
1069
    }
1070
1071
    /**
1072
     * MyTextSanitizer::executeExtension()
1073
     *
1074
     * @param  mixed $name
1075
     * @return mixed
1076
     */
1077
    public function executeExtension($name)
1078
    {
1079
        $extension = $this->loadExtension($name);
1080
        $args      = array_slice(func_get_args(), 1);
1081
        array_unshift($args, $this);
1082
1083
        return call_user_func_array([$extension, 'load'], $args);
1084
    }
1085
1086
    /**
1087
     * Filter out possible malicious text
1088
     * kses project at SF could be a good solution to check
1089
     *
1090
     * @param  string $text  text to filter
1091
     * @param  bool   $force force filtering
1092
     * @return string filtered text
1093
     */
1094
    public function textFilter($text, $force = false)
1095
    {
1096
        $ret = $this->executeExtension('textfilter', $text, $force);
1097
        if ($ret === false) {
1098
            return $text;
1099
        }
1100
1101
        return $ret;
1102
    }
1103
1104
    // #################### Deprecated Methods ######################
1105
1106
    /**
1107
     * if magic_quotes_gpc is on, strip back slashes
1108
     *
1109
     * @param  string $text
1110
     * @return string
1111
     * @deprecated as of XOOPS 2.5.11 and will be removed in next XOOPS version
1112
     *
1113
     * This remains here until we officially drop support for PHP 5.3 in next release
1114
     */
1115
    public function stripSlashesGPC($text)
1116
    {
1117
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1118
1119
        return $text;
1120
    }
1121
1122
    /**
1123
     * MyTextSanitizer::codeSanitizer()
1124
     *
1125
     * @param  mixed $str
1126
     * @param  mixed $image
1127
     * @return mixed|string
1128
     * @deprecated will be removed in next XOOPS version
1129
     */
1130
    public function codeSanitizer($str, $image = 1)
1131
    {
1132
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1133
        $str = $this->htmlSpecialChars(str_replace('\"', '"', base64_decode($str)));
1134
        $str = & $this->xoopsCodeDecode($str, $image);
1135
1136
        return $str;
1137
    }
1138
1139
    /**
1140
     * MyTextSanitizer::sanitizeForDisplay()
1141
     *
1142
     * @param  mixed   $text
1143
     * @param  integer $allowhtml
1144
     * @param  integer $smiley
1145
     * @param  mixed   $bbcode
1146
     * @return mixed|string
1147
     * @deprecated will be removed in next XOOPS version
1148
     */
1149
    public function sanitizeForDisplay($text, $allowhtml = 0, $smiley = 1, $bbcode = 1)
1150
    {
1151
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1152
        if ($allowhtml == 0) {
1153
            $text = $this->htmlSpecialChars($text);
1154
        } else {
1155
            // $config =& $GLOBALS['xoopsConfig'];
1156
            // $allowed = $config['allowed_html'];
1157
            // $text = strip_tags($text, $allowed);
1158
            $text = $this->makeClickable($text);
1159
        }
1160
        if ($smiley == 1) {
1161
            $text = $this->smiley($text);
1162
        }
1163
        if ($bbcode == 1) {
1164
            $text = & $this->xoopsCodeDecode($text);
1165
        }
1166
        $text = $this->nl2Br($text);
1167
1168
        return $text;
1169
    }
1170
1171
    /**
1172
     * MyTextSanitizer::sanitizeForPreview()
1173
     *
1174
     * @param  mixed   $text
1175
     * @param  integer $allowhtml
1176
     * @param  integer $smiley
1177
     * @param  mixed   $bbcode
1178
     * @return mixed|string
1179
     * @deprecated will be removed in next XOOPS version
1180
     */
1181
    public function sanitizeForPreview($text, $allowhtml = 0, $smiley = 1, $bbcode = 1)
1182
    {
1183
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1184
        if ($allowhtml == 0) {
1185
            $text = $this->htmlSpecialChars($text);
1186
        } else {
1187
            // $config =& $GLOBALS['xoopsConfig'];
1188
            // $allowed = $config['allowed_html'];
1189
            // $text = strip_tags($text, $allowed);
1190
            $text = $this->makeClickable($text);
1191
        }
1192
        if ($smiley == 1) {
1193
            $text = $this->smiley($text);
1194
        }
1195
        if ($bbcode == 1) {
1196
            $text = & $this->xoopsCodeDecode($text);
1197
        }
1198
        $text = $this->nl2Br($text);
1199
1200
        return $text;
1201
    }
1202
1203
    /**
1204
     * MyTextSanitizer::makeTboxData4Save()
1205
     *
1206
     * @param  mixed $text
1207
     * @return string
1208
     * @deprecated will be removed in next XOOPS version
1209
     */
1210
    public function makeTboxData4Save($text)
1211
    {
1212
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1213
1214
        // $text = $this->undoHtmlSpecialChars($text);
1215
        return $this->addSlashes($text);
1216
    }
1217
1218
    /**
1219
     * MyTextSanitizer::makeTboxData4Show()
1220
     *
1221
     * @param  mixed $text
1222
     * @param  mixed $smiley
1223
     * @return mixed|string
1224
     * @deprecated will be removed in next XOOPS version
1225
     */
1226
    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

1226
    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...
1227
    {
1228
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1229
        $text = $this->htmlSpecialChars($text);
1230
1231
        return $text;
1232
    }
1233
1234
    /**
1235
     * MyTextSanitizer::makeTboxData4Edit()
1236
     *
1237
     * @param  mixed $text
1238
     * @return string
1239
     * @deprecated will be removed in next XOOPS version
1240
     */
1241
    public function makeTboxData4Edit($text)
1242
    {
1243
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1244
1245
        return $this->htmlSpecialChars($text);
1246
    }
1247
1248
    /**
1249
     * MyTextSanitizer::makeTboxData4Preview()
1250
     *
1251
     * @param  mixed $text
1252
     * @param  mixed $smiley
1253
     * @return mixed|string
1254
     * @deprecated will be removed in next XOOPS version
1255
     */
1256
    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

1256
    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...
1257
    {
1258
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1259
        $text = $this->htmlSpecialChars($text);
1260
1261
        return $text;
1262
    }
1263
1264
    /**
1265
     * MyTextSanitizer::makeTboxData4PreviewInForm()
1266
     *
1267
     * @param  mixed $text
1268
     * @return string
1269
     * @deprecated will be removed in next XOOPS version
1270
     */
1271
    public function makeTboxData4PreviewInForm($text)
1272
    {
1273
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1274
1275
        return $this->htmlSpecialChars($text);
1276
    }
1277
1278
    /**
1279
     * MyTextSanitizer::makeTareaData4Save()
1280
     *
1281
     * @param  mixed $text
1282
     * @return string
1283
     * @deprecated will be removed in next XOOPS version
1284
     */
1285
    public function makeTareaData4Save($text)
1286
    {
1287
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1288
1289
        return $this->addSlashes($text);
1290
    }
1291
1292
    /**
1293
     * MyTextSanitizer::makeTareaData4Show()
1294
     *
1295
     * @param  mixed   $text
1296
     * @param  integer $html
1297
     * @param  integer $smiley
1298
     * @param  mixed   $xcode
1299
     * @return mixed|string
1300
     * @deprecated will be removed in next XOOPS version
1301
     */
1302
    public function &makeTareaData4Show($text, $html = 1, $smiley = 1, $xcode = 1)
1303
    {
1304
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1305
        $text = & $this->displayTarea($text, $html, $smiley, $xcode);
1306
1307
        return $text;
1308
    }
1309
1310
    /**
1311
     * MyTextSanitizer::makeTareaData4Edit()
1312
     *
1313
     * @param  mixed $text
1314
     * @return string
1315
     * @deprecated will be removed in next XOOPS version
1316
     */
1317
    public function makeTareaData4Edit($text)
1318
    {
1319
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1320
1321
        return $this->htmlSpecialChars($text);
1322
    }
1323
1324
    /**
1325
     * MyTextSanitizer::makeTareaData4Preview()
1326
     *
1327
     * @param  mixed   $text
1328
     * @param  integer $html
1329
     * @param  integer $smiley
1330
     * @param  mixed   $xcode
1331
     * @return mixed|string
1332
     * @deprecated will be removed in next XOOPS version
1333
     */
1334
    public function &makeTareaData4Preview($text, $html = 1, $smiley = 1, $xcode = 1)
1335
    {
1336
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1337
        $text = & $this->previewTarea($text, $html, $smiley, $xcode);
1338
1339
        return $text;
1340
    }
1341
1342
    /**
1343
     * MyTextSanitizer::makeTareaData4PreviewInForm()
1344
     *
1345
     * @param  mixed $text
1346
     * @return string
1347
     * @deprecated will be removed in next XOOPS version
1348
     */
1349
    public function makeTareaData4PreviewInForm($text)
1350
    {
1351
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1352
1353
        return $this->htmlSpecialChars($text);
1354
    }
1355
1356
    /**
1357
     * MyTextSanitizer::makeTareaData4InsideQuotes()
1358
     *
1359
     * @param  mixed $text
1360
     * @return string
1361
     * @deprecated will be removed in next XOOPS version
1362
     */
1363
    public function makeTareaData4InsideQuotes($text)
1364
    {
1365
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1366
1367
        return $this->htmlSpecialChars($text);
1368
    }
1369
1370
    /**
1371
     * MyTextSanitizer::oopsStripSlashesGPC()
1372
     *
1373
     * @param  mixed $text
1374
     * @return string
1375
     * @deprecated will be removed in next XOOPS version
1376
     */
1377
    public function oopsStripSlashesGPC($text)
1378
    {
1379
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1380
1381
        return $text;
1382
    }
1383
1384
    /**
1385
     * MyTextSanitizer::oopsStripSlashesRT()
1386
     *
1387
     * @param  mixed $text
1388
     * @return mixed|string
1389
     * @deprecated will be removed in next XOOPS version
1390
     */
1391
    public function oopsStripSlashesRT($text)
1392
    {
1393
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1394
1395
        return $text;
1396
    }
1397
1398
    /**
1399
     * MyTextSanitizer::oopsAddSlashes()
1400
     *
1401
     * @param  mixed $text
1402
     * @return string
1403
     * @deprecated will be removed in next XOOPS version
1404
     */
1405
    public function oopsAddSlashes($text)
1406
    {
1407
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1408
1409
        return $this->addSlashes($text);
1410
    }
1411
1412
    /**
1413
     * MyTextSanitizer::oopsHtmlSpecialChars()
1414
     *
1415
     * @param  mixed $text
1416
     * @return string
1417
     * @deprecated will be removed in next XOOPS version
1418
     */
1419
    public function oopsHtmlSpecialChars($text)
1420
    {
1421
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1422
1423
        return $this->htmlSpecialChars($text);
1424
    }
1425
1426
    /**
1427
     * MyTextSanitizer::oopsNl2Br()
1428
     *
1429
     * @param  mixed $text
1430
     * @return string
1431
     * @deprecated will be removed in next XOOPS version
1432
     */
1433
    public function oopsNl2Br($text)
1434
    {
1435
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
1436
1437
        return $this->nl2Br($text);
1438
    }
1439
}
1440