PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / php / MbStringAdapterPreg.php

MbStringAdapterPreg.php in 404 Solution trunk, at includes/php/MbStringAdapterPreg.php

108 lines 3.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 if (!defined('ABSPATH')) {
5 exit;
6 }
7
8 /**
9 * Native string-backed implementation of ABJ_404_Solution_MbStringAdapter.
10 *
11 * Use when the PHP mbstring extension is unavailable. Regex primitives
12 * live on ABJ_404_Solution_RegexHelperPreg (sibling extraction, task
13 * i826).
14 */
15 class ABJ_404_Solution_MbStringAdapterPreg extends ABJ_404_Solution_MbStringAdapter {
16
17 /** @var self|null */
18 private static $instance = null;
19 /**
20 * Test seam: install or clear the cached singleton instance without
21 * private-field reflection. Pass null to reset between tests; pass a
22 * configured instance (or double) to install it (M105 singleton-reset seam).
23 *
24 * @param self|null $instance
25 * @return void
26 */
27 public static function setInstance($instance) {
28 self::$instance = $instance;
29 }
30
31
32 public static function getInstance(): self {
33 if (self::$instance === null) {
34 self::$instance = new self();
35 }
36 return self::$instance;
37 }
38
39 public function ord(string $char): int {
40 return ord($char);
41 }
42
43 public function strtolower(?string $string): string {
44 if ($string === null) {
45 return '';
46 }
47 return strtolower($string);
48 }
49
50 public function strlen(string $string): int {
51 return strlen($string);
52 }
53
54 /** @return int|false */
55 public function strpos(string $haystack, string $needle, int $offset = 0) {
56 if ($offset === 0) {
57 return strpos($haystack, $needle);
58 }
59 return strpos($haystack, $needle, $offset);
60 }
61
62 public function substr(?string $str, int $start, ?int $length = null): string {
63 if ($str === null) {
64 return '';
65 }
66 if ($length === null) {
67 return substr($str, $start);
68 }
69 return substr($str, $start, $length);
70 }
71
72 public function sanitizeInvalidUTF8(?string $string): string {
73 if ($string === null || $string === '') {
74 return '';
75 }
76
77 if (function_exists('iconv')) {
78 // iconv may emit warnings on malformed input; suppress and fall
79 // back if it returns false.
80 // allow-silent-catch: iconv //IGNORE intentionally swallows
81 // malformed-byte warnings; we fall through to preg below.
82 $sanitized = @iconv('UTF-8', 'UTF-8//IGNORE', $string);
83 if ($sanitized !== false) {
84 $sanitized = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/u', '', $sanitized) ?? $sanitized;
85 return $sanitized;
86 }
87 }
88
89 // Validate UTF-8 with the //u modifier; preg_replace returns null on
90 // invalid input, which signals fall-through.
91 $sanitized = @preg_replace('//u', '', $string);
92
93 if ($sanitized === null) {
94 // Strip invalid UTF-8 lead bytes and stranded continuation bytes.
95 $sanitized = preg_replace('/[\xC0\xC1\xF5-\xFF][\x80-\xBF]*/', '', $string) ?? $string;
96 $sanitized = preg_replace('/[\x80-\xBF]+/', '', $sanitized) ?? $sanitized;
97
98 if (@preg_match('//u', $sanitized) === false) {
99 // Last-resort ASCII-only filter.
100 $sanitized = preg_replace('/[^\x09\x0A\x0D\x20-\x7E]/', '', $string) ?? '';
101 }
102 }
103
104 $sanitized = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '', $sanitized) ?? $sanitized;
105 return $sanitized;
106 }
107 }
108