This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Ridibooks\Platform\Common; |
||
4 | |||
5 | use Ridibooks\Exception\MsgException; |
||
6 | |||
7 | class HtmlUtils |
||
8 | { |
||
9 | public static $cms_allowable_tags = [ |
||
10 | 'strong' => [], |
||
11 | 'b' => [], |
||
12 | 'bold' => [], |
||
13 | 'u' => [], |
||
14 | 'br' => [], |
||
15 | 'font' => ['color'], |
||
16 | 'a' => ['href', 'target'], |
||
17 | 'img' => ['src'], |
||
18 | 'video' => ['src'], |
||
19 | 'em' => [], |
||
20 | ]; |
||
21 | |||
22 | public static $cp_allowable_tags = [ |
||
23 | 'strong' => [] |
||
24 | ]; |
||
25 | |||
26 | private static $tags_open_and_close_in_one = [ |
||
27 | 'img', |
||
28 | 'video' |
||
29 | ]; |
||
30 | |||
31 | /** |
||
32 | * @param $html |
||
33 | * @param array $allowable_tags |
||
34 | * @return bool |
||
35 | */ |
||
36 | public static function isValidHtmlTag($html, array $allowable_tags) |
||
37 | { |
||
38 | try { |
||
39 | self::assertValidHtmlTag($html, $allowable_tags); |
||
40 | } catch (MsgException $exception) { |
||
0 ignored issues
–
show
|
|||
41 | return false; |
||
42 | } |
||
43 | return true; |
||
44 | } |
||
45 | |||
46 | /** |
||
47 | * @param $html |
||
48 | * @param array $allowable_tags |
||
49 | * @throws MsgException |
||
50 | */ |
||
51 | public static function assertValidHtmlTag($html, array $allowable_tags) |
||
52 | { |
||
53 | $html = self::filterNonAllowableTags($html, $allowable_tags); |
||
54 | |||
55 | $stack = array(); |
||
56 | preg_replace_callback( |
||
57 | '/\<(\/?)([a-z]\w*)([^\>]*)\>/i', |
||
58 | function ($args) use (&$stack) { |
||
59 | $tag_opened = (strlen($args[1]) == 0); |
||
60 | $tag = $args[2]; |
||
61 | $attr = $args[3]; |
||
62 | $full_tag = $args[0]; |
||
63 | |||
64 | //br태그는 무시 |
||
65 | if ($tag == 'br') { |
||
66 | return; |
||
67 | } |
||
68 | |||
69 | if ($tag_opened) { |
||
70 | /* |
||
71 | * attr의 끝이 / 인것은 무시한다 |
||
72 | * - <video src='xxxxx'/> |
||
73 | * - <div /> |
||
74 | * - <input /> |
||
75 | */ |
||
76 | if ($attr[strlen($attr) - 1] == '/') { |
||
77 | return; |
||
78 | } |
||
79 | array_push($stack, array($tag, $full_tag)); |
||
80 | } else { |
||
81 | if (count($stack)) { |
||
82 | $last_tags = array_pop($stack); |
||
83 | $last_tag = $last_tags[0]; |
||
84 | $last_full_tag = $last_tags[1]; |
||
85 | } else { |
||
86 | $last_tags = null; |
||
0 ignored issues
–
show
$last_tags is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
87 | $last_tag = null; |
||
88 | $last_full_tag = null; |
||
89 | } |
||
90 | if ($last_tag != $tag) { |
||
91 | throw new MsgException( |
||
92 | 'tag mismatch : ' . $last_full_tag . ' => ' . $full_tag |
||
93 | ); |
||
94 | } |
||
95 | } |
||
96 | }, |
||
97 | $html |
||
98 | ); |
||
99 | if (!empty($stack)) { |
||
100 | throw new MsgException( |
||
101 | 'tag mismatch : 열리거나 닫히기만 한 태그가 존재합니다.' |
||
102 | ); |
||
103 | } |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * 허용하지 않는 태그용 문자를 변환해준다. |
||
108 | * @param $string |
||
109 | * @param array $allowable_tags |
||
110 | * $allowable_tags 배열 형식: |
||
111 | * $allowable_tags = [ |
||
112 | * 'tag' => ['attr1', 'attr2'] |
||
113 | * ] |
||
114 | * @return string |
||
115 | */ |
||
116 | public static function filterNonAllowableTags($string, array $allowable_tags) |
||
117 | { |
||
118 | // br태그는 개행으로 자동변경 |
||
119 | $string = preg_replace('/(\<\/?\s*br[^\>]*\>)/is', "\n", $string); |
||
120 | |||
121 | // 태그 사용을 원천 방지하기 위하여 일단은 무조건 <, >로 변환 |
||
122 | $string = str_replace('<', '<', $string); |
||
123 | $string = str_replace('>', '>', $string); |
||
124 | |||
125 | $offset = 0; |
||
126 | preg_match_all("/<((?:(?!<|>).)*)>/isU", $string, $matches, PREG_OFFSET_CAPTURE); |
||
127 | foreach ($matches[0] as $index => $match) { |
||
128 | $replace = ''; |
||
129 | |||
130 | // 원본 전체 문자열 |
||
131 | $original = $matches[0][$index][0]; |
||
132 | |||
133 | // 내부 문자열 |
||
134 | $tag_and_attr_string = $matches[1][$index][0]; |
||
135 | |||
136 | // attr가 있어야되는 것들과 없어야되는 것들의 분리 |
||
137 | $tags_without_attrs = []; |
||
138 | $tags_with_attrs = []; |
||
139 | foreach ($allowable_tags as $tag => $attrs) { |
||
140 | if (empty($attrs)) { |
||
141 | $tags_without_attrs[] = $tag; |
||
142 | } else { |
||
143 | $tags_with_attrs[] = $tag; |
||
144 | } |
||
145 | |||
146 | // close 태그는 무조건 attr가 없어야됨 |
||
147 | $tags_without_attrs[] = '/' . $tag; |
||
148 | } |
||
149 | |||
150 | // attr가 없어야만 되는 것들 |
||
151 | if (in_array(strtolower(trim($tag_and_attr_string)), $tags_without_attrs)) { |
||
152 | $replace = trim($tag_and_attr_string); |
||
153 | } |
||
154 | |||
155 | // attr가 필수적인것들 |
||
156 | $is_matched = !!preg_match("/^(" . implode('|', $tags_with_attrs) .")\s+(.+)$/is", trim($tag_and_attr_string), $sub_matches); |
||
157 | if ($is_matched) { |
||
158 | // 태그명 |
||
159 | $tag_name = $sub_matches[1]; |
||
160 | |||
161 | // attr 문자열 필터링 |
||
162 | $attribute_string = $sub_matches[2]; |
||
163 | $attributes = self::extractTagAttributes($attribute_string); |
||
164 | $filtered_attributes = self::filterAllowableTagAttributes($tag_name, $attributes); |
||
165 | $replace_attribute_string = self::implodeTagAttributes($filtered_attributes); |
||
166 | if (!StringUtils::isEmpty($replace_attribute_string)) { |
||
167 | $replace = $tag_name . ' ' . $replace_attribute_string; |
||
168 | |||
169 | if (in_array(strtolower($tag_name), self::$tags_open_and_close_in_one)) { |
||
170 | $replace .= '/'; |
||
171 | } |
||
172 | } |
||
173 | } |
||
174 | |||
175 | if (!StringUtils::isEmpty($replace)) { |
||
176 | $replace = '<' . $replace . '>'; |
||
177 | |||
178 | // 문자열 새로 조합 |
||
179 | $original_string_offset = $matches[0][$index][1]; |
||
180 | $pre_string = substr($string, 0, $offset + $original_string_offset); |
||
181 | $post_string = substr($string, $offset + $original_string_offset + strlen($original), strlen($string) - ($offset + $original_string_offset + strlen($original))); |
||
182 | $string = $pre_string . $replace . $post_string; |
||
183 | |||
184 | // 원본 문자열에서 구한 offset과 변환된 문자열의 offset과 달라지는 점을 고려 |
||
185 | $offset += strlen($replace) - strlen($original); |
||
186 | } |
||
187 | } |
||
188 | |||
189 | return $string; |
||
190 | } |
||
191 | |||
192 | private static function extractTagAttributes($string) |
||
193 | { |
||
194 | $html_attributes = array(); |
||
195 | preg_match_all("/([^=\s]+)\s*=\s*[\"']*((?:.(?![\"']*\s+(?:\S+)=|[>\"']))+.)[\"']*/is", htmlspecialchars_decode(stripslashes($string)), $matches, PREG_SET_ORDER); |
||
196 | foreach ($matches as $match) { |
||
0 ignored issues
–
show
The expression
$matches of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
197 | $attr = $match[1]; |
||
198 | $value = $match[2]; |
||
199 | $html_attributes[$attr] = $value; |
||
200 | } |
||
201 | |||
202 | return $html_attributes; |
||
203 | } |
||
204 | |||
205 | private static function filterAllowableTagAttributes($tag_name, $html_attributes) |
||
206 | { |
||
207 | // 문자열비교시 대소문자를 가리기때문에, 소문자로 해당값 입력 |
||
208 | $allowable_attributes = array( |
||
209 | 'a' => array('href', 'target'), |
||
210 | 'font' => array('color'), |
||
211 | 'img' => array('src'), |
||
212 | 'video' => array('src') |
||
213 | ); |
||
214 | |||
215 | $filtered_html_attributes = array(); |
||
216 | foreach ($html_attributes as $attr => $value) { |
||
217 | if (!in_array(strtolower($attr), (array)$allowable_attributes[strtolower($tag_name)])) { |
||
218 | continue; |
||
219 | } |
||
220 | |||
221 | $filtered_html_attributes[$attr] = $value; |
||
222 | } |
||
223 | |||
224 | return $filtered_html_attributes; |
||
225 | } |
||
226 | |||
227 | private static function implodeTagAttributes($html_attributes) |
||
228 | { |
||
229 | $attr_values = array(); |
||
230 | foreach ($html_attributes as $attr => $value) { |
||
231 | $attr_values[] = $attr . '="' . $value . '"'; |
||
232 | } |
||
233 | |||
234 | return implode(' ', $attr_values); |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * 허용하지 않는 태그용 문자를 제거해준다. |
||
239 | * @param $string |
||
240 | * @param array $allowable_tags |
||
241 | * $allowable_tags 배열 형식: |
||
242 | * $allowable_tags = [ |
||
243 | * 'tag' => ['attr1', 'attr2'] |
||
244 | * ] |
||
245 | * @return string |
||
246 | */ |
||
247 | public static function stripNonAllowableTags($string, $allowable_tags) |
||
248 | { |
||
249 | $string = self::filterNonAllowableTags($string, $allowable_tags); |
||
250 | $string = StringUtils::swapTwoSubStrings($string, '<', '<'); |
||
251 | $string = StringUtils::swapTwoSubStrings($string, '>', '>'); |
||
252 | $string = strip_tags($string); |
||
253 | $string = StringUtils::swapTwoSubStrings($string, '<', '<'); |
||
254 | $string = StringUtils::swapTwoSubStrings($string, '>', '>'); |
||
255 | |||
256 | return $string; |
||
257 | } |
||
258 | } |
||
259 |
Scrutinizer analyzes your
composer.json
/composer.lock
file if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.