PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.19
ووسلام – همگام سازی ووکامرس و باسلام v1.10.19
1.10.19 1.10.20 1.10.18 1.10.17 1.10.15 1.10.14 1.10.13 1.10.12 1.10.10 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.2 1.9.1 1.9.0 1.8.8 1.8.5 1.8.6 All 53 releases
sync-basalam / includes / Services / Products / DescriptionErrorSanitizer.php

DescriptionErrorSanitizer.php in ووسلام – همگام سازی ووکامرس و باسلام 1.10.19, at includes/Services/Products/DescriptionErrorSanitizer.php

146 lines 4.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SyncBasalam\Services\Products;
4
5 defined('ABSPATH') || exit;
6
7 class DescriptionErrorSanitizer
8 {
9 private const SEPARATOR = '[\s\x{200c}\x{00a0}\-\_\.\–\—]*';
10
11 public static function extractDescriptionValues(?array $responseData): array
12 {
13 if (!is_array($responseData)) return [];
14
15 $messages = $responseData['messages'] ?? null;
16 if (!is_array($messages)) return [];
17
18 $values = [];
19
20 foreach ($messages as $message) {
21 if (!is_array($message)) continue;
22
23 $fields = $message['fields'] ?? [];
24 if (!is_array($fields) || !in_array('description', $fields, true)) continue;
25
26 $detected = $message['detected'] ?? [];
27 if (!is_array($detected)) continue;
28
29 foreach ($detected as $item) {
30 foreach (self::valuesFromDetectedItem($item) as $value) {
31 $values[$value] = $value;
32 }
33 }
34 }
35
36 $values = array_values($values);
37 usort($values, static function ($a, $b) {
38 return mb_strlen($b) <=> mb_strlen($a);
39 });
40
41 return $values;
42 }
43
44 private static function valuesFromDetectedItem($item): array
45 {
46 if (is_string($item)) {
47 $item = trim($item);
48 return $item !== '' ? [$item] : [];
49 }
50
51 if (!is_array($item)) return [];
52
53 $found = [];
54
55 $snippet = $item['snippet'] ?? '';
56 if (is_string($snippet) && $snippet !== '') {
57 if (preg_match_all('/<em>(.*?)<\/em>/isu', $snippet, $matches)) {
58 foreach ($matches[1] as $match) {
59 $value = trim(wp_strip_all_tags(html_entity_decode($match, ENT_QUOTES | ENT_HTML5, 'UTF-8')));
60 if ($value === '') continue;
61
62 $found[] = $value;
63
64 // Basalam highlights a whole window of text and returns it normalized
65 // (e.g. "یک" comes back as "1"), so the full phrase often matches nothing
66 // in the original description. The part that actually triggers the
67 // "social id" signal is the handle-like token, so target it separately.
68 foreach (self::handleLikeTokens($value) as $token) {
69 $found[] = $token;
70 }
71 }
72 }
73 }
74
75 $value = $item['value'] ?? '';
76 if (is_string($value)) {
77 $value = trim($value);
78 if ($value !== '') $found[] = $value;
79 }
80
81 return $found;
82 }
83
84 /**
85 * Pulls out handle/domain-like tokens ("s.exy", "س.کسی", "insta.gram") from a
86 * highlighted snippet.
87 *
88 * @return string[]
89 */
90 private static function handleLikeTokens(string $text): array
91 {
92 if (!preg_match_all('/[\p{L}\p{N}_]+(?:\.[\p{L}\p{N}_]+)+/u', $text, $matches)) return [];
93
94 return array_values(array_filter($matches[0], static function ($token) {
95 return mb_strlen($token) >= 3;
96 }));
97 }
98
99 public static function sanitize(string $description, array $values): string
100 {
101 $result = $description;
102
103 foreach ($values as $value) {
104 if (!is_string($value)) continue;
105 $result = self::removeValue($result, $value);
106 }
107
108 $result = preg_replace('/[ \t]{2,}/u', ' ', $result);
109 $result = preg_replace('/\n{3,}/u', "\n\n", $result);
110
111 return trim($result);
112 }
113
114 private static function removeValue(string $text, string $value): string
115 {
116 $value = trim($value);
117 if ($value === '') return $text;
118
119 $pattern = self::buildPattern($value);
120 if ($pattern !== null) {
121 $replaced = preg_replace($pattern, ' ', $text);
122 if (is_string($replaced) && $replaced !== $text) return $replaced;
123 }
124
125 $replaced = str_ireplace($value, ' ', $text);
126
127 return is_string($replaced) ? $replaced : $text;
128 }
129
130 private static function buildPattern(string $value): ?string
131 {
132 $segments = preg_split('/[\s\x{200c}\x{00a0}\-\_\.\–\—]+/u', $value, -1, PREG_SPLIT_NO_EMPTY);
133 if (empty($segments)) return null;
134
135 $escaped = array_map(static function ($segment) {
136 return preg_quote($segment, '/');
137 }, $segments);
138
139 $pattern = '/' . implode(self::SEPARATOR, $escaped) . '/iu';
140
141 if (@preg_match($pattern, '') === false) return null;
142
143 return $pattern;
144 }
145 }
146