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 | * Class BBCode |
||
4 | * |
||
5 | * @filesource BBCode.php |
||
6 | * @created 19.04.2018 |
||
7 | * @package chillerlan\BBCode |
||
8 | * @author smiley <[email protected]> |
||
9 | * @copyright 2018 smiley |
||
10 | * @license MIT |
||
11 | */ |
||
12 | |||
13 | namespace chillerlan\BBCode; |
||
14 | |||
15 | use chillerlan\BBCode\Output\BBCodeOutputInterface; |
||
16 | use chillerlan\Settings\SettingsContainerInterface; |
||
17 | use Psr\Log\{ |
||
18 | LoggerAwareInterface, LoggerAwareTrait, LoggerInterface, NullLogger |
||
19 | }; |
||
20 | use Psr\SimpleCache\CacheInterface; |
||
21 | |||
22 | class BBCode implements LoggerAwareInterface{ |
||
23 | use LoggerAwareTrait; |
||
24 | |||
25 | /** |
||
26 | * @var \chillerlan\BBCode\BBCodeOptions|\chillerlan\Settings\SettingsContainerInterface |
||
27 | */ |
||
28 | protected $options; |
||
29 | |||
30 | /** |
||
31 | * @var \Psr\SimpleCache\CacheInterface|\chillerlan\BBCode\BBCache |
||
32 | */ |
||
33 | protected $cache; |
||
34 | |||
35 | /** |
||
36 | * @var \chillerlan\BBCode\SanitizerInterface |
||
37 | */ |
||
38 | protected $sanitizerInterface; |
||
39 | |||
40 | /** |
||
41 | * @var \chillerlan\BBCode\Output\BBCodeOutputInterface |
||
42 | */ |
||
43 | protected $outputInterface; |
||
44 | |||
45 | /** |
||
46 | * @var \chillerlan\BBCode\ParserMiddlewareInterface |
||
47 | */ |
||
48 | protected $parserMiddleware; |
||
49 | |||
50 | /** |
||
51 | * @var array |
||
52 | */ |
||
53 | protected $tags = []; |
||
54 | |||
55 | /** |
||
56 | * @var array |
||
57 | */ |
||
58 | protected $noparse = []; |
||
59 | |||
60 | /** |
||
61 | * @var array |
||
62 | */ |
||
63 | protected $allowed = []; |
||
64 | |||
65 | /** |
||
66 | * @var int |
||
67 | */ |
||
68 | protected $limit; |
||
69 | |||
70 | /** |
||
71 | * BBCode constructor. |
||
72 | * |
||
73 | * @param \chillerlan\Settings\SettingsContainerInterface|null $options |
||
74 | * @param \Psr\SimpleCache\CacheInterface|null $cache |
||
75 | * @param \Psr\Log\LoggerInterface|null $logger |
||
76 | */ |
||
77 | public function __construct(SettingsContainerInterface $options = null, CacheInterface $cache = null, LoggerInterface $logger = null){ |
||
78 | $this |
||
79 | ->setCache($cache ?? new BBCache) |
||
80 | ->setLogger($logger ?? new NullLogger); |
||
81 | |||
82 | $this->setOptions($options ?? new BBCodeOptions); |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * @param array $allowedTags |
||
87 | * |
||
88 | * @return \chillerlan\BBCode\BBCode |
||
89 | */ |
||
90 | public function allowTags(array $allowedTags):BBCode{ |
||
91 | $this->allowed = []; |
||
92 | |||
93 | foreach($allowedTags as $tag){ |
||
94 | $tag = strtolower($tag); |
||
95 | |||
96 | if(in_array($tag, $this->tags, true)){ |
||
97 | $this->allowed[] = $tag; |
||
98 | } |
||
99 | } |
||
100 | |||
101 | return $this; |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * @param \Psr\SimpleCache\CacheInterface $cache |
||
106 | * |
||
107 | * @return \chillerlan\BBCode\BBCode |
||
108 | */ |
||
109 | public function setCache(CacheInterface $cache):BBCode{ |
||
110 | $this->cache = $cache; |
||
111 | |||
112 | return $this; |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * @todo |
||
117 | * |
||
118 | * @param \chillerlan\Settings\SettingsContainerInterface $options |
||
119 | * |
||
120 | * @throws \chillerlan\BBCode\BBCodeException |
||
121 | * @return \chillerlan\BBCode\BBCode |
||
122 | */ |
||
123 | public function setOptions(SettingsContainerInterface $options):BBCode{ |
||
124 | $this->options = $options; |
||
125 | |||
126 | mb_internal_encoding('UTF-8'); |
||
127 | |||
128 | if( |
||
129 | ini_set('pcre.backtrack_limit', $this->options->pcre_backtrack_limit) === false |
||
0 ignored issues
–
show
|
|||
130 | || ini_set('pcre.recursion_limit', $this->options->pcre_recursion_limit) === false |
||
0 ignored issues
–
show
Accessing
pcre_recursion_limit on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
131 | || ini_set('pcre.jit', $this->options->pcre_jit) === false |
||
0 ignored issues
–
show
Accessing
pcre_jit on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
132 | ){ |
||
133 | throw new BBCodeException('could not alter ini settings'); |
||
134 | } |
||
135 | |||
136 | if(ini_get('pcre.backtrack_limit') !== (string)$this->options->pcre_backtrack_limit |
||
0 ignored issues
–
show
Accessing
pcre_backtrack_limit on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
137 | || ini_get('pcre.recursion_limit') !== (string)$this->options->pcre_recursion_limit |
||
0 ignored issues
–
show
Accessing
pcre_recursion_limit on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
138 | || ini_get('pcre.jit') !== (string)$this->options->pcre_jit |
||
0 ignored issues
–
show
Accessing
pcre_jit on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
139 | ){ |
||
140 | throw new BBCodeException('ini settings differ from options'); |
||
141 | } |
||
142 | |||
143 | if($this->options->sanitizeInput || $this->options->sanitizeOutput){ |
||
0 ignored issues
–
show
Accessing
sanitizeInput on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() Accessing
sanitizeOutput on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
144 | $this->sanitizerInterface = new $this->options->sanitizerInterface($this->options); |
||
0 ignored issues
–
show
Accessing
sanitizerInterface on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
145 | |||
146 | if(!$this->sanitizerInterface instanceof SanitizerInterface){ |
||
147 | throw new BBcodeException('invalid SanitizerInterface'); |
||
148 | } |
||
149 | } |
||
150 | |||
151 | if($this->options->preParse || $this->options->postParse){ |
||
0 ignored issues
–
show
Accessing
preParse on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() Accessing
postParse on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
152 | $this->parserMiddleware = new $this->options->parserMiddlewareInterface($this->options, $this->cache, $this->logger); |
||
0 ignored issues
–
show
Accessing
parserMiddlewareInterface on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
153 | |||
154 | if(!$this->parserMiddleware instanceof ParserMiddlewareInterface){ |
||
155 | throw new BBcodeException('invalid ParserMiddlewareInterface'); |
||
156 | } |
||
157 | } |
||
158 | |||
159 | $this->outputInterface = new $this->options->outputInterface($this->options, $this->cache, $this->logger); |
||
0 ignored issues
–
show
Accessing
outputInterface on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
160 | |||
161 | if(!$this->outputInterface instanceof BBCodeOutputInterface){ |
||
162 | throw new BBcodeException('invalid BBCodeOutputInterface'); |
||
163 | } |
||
164 | |||
165 | $this->tags = $this->outputInterface->getTags(); |
||
166 | $this->noparse = $this->outputInterface->getNoparse(); |
||
167 | $this->limit = (int)$this->options->nestingLimit; |
||
0 ignored issues
–
show
Accessing
nestingLimit on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
168 | |||
169 | if(is_array($this->options->allowedTags) && !empty($this->options->allowedTags)){ |
||
0 ignored issues
–
show
Accessing
allowedTags on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
170 | $this->allowTags($this->options->allowedTags); |
||
0 ignored issues
–
show
Accessing
allowedTags on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
171 | } |
||
172 | elseif($this->options->allowAvailableTags === true){ |
||
0 ignored issues
–
show
Accessing
allowAvailableTags on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
173 | $this->allowed = $this->tags; |
||
174 | } |
||
175 | |||
176 | return $this; |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Transforms a BBCode string to HTML (or whatevs) |
||
181 | * |
||
182 | * @param string $bbcode |
||
183 | * |
||
184 | * @return string |
||
185 | */ |
||
186 | public function parse(string $bbcode):string{ |
||
187 | |||
188 | // sanitize the input if needed |
||
189 | if($this->options->sanitizeInput){ |
||
0 ignored issues
–
show
Accessing
sanitizeInput on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
190 | $bbcode = $this->sanitizerInterface->sanitizeInput($bbcode); |
||
191 | } |
||
192 | |||
193 | // run the pre-parser |
||
194 | if($this->options->preParse){ |
||
0 ignored issues
–
show
Accessing
preParse on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
195 | $bbcode = $this->parserMiddleware->pre($bbcode); |
||
196 | } |
||
197 | |||
198 | // @todo: array < 2 elements causes a PREG_BACKTRACK_LIMIT_ERROR! (breaks match pattern) |
||
199 | $singleTags = array_merge(['br', 'hr'], $this->outputInterface->getSingleTags()); |
||
200 | |||
201 | // close singletags: [br] -> [br][/br] |
||
202 | $bbcode = preg_replace('#\[('.implode('|', $singleTags).')((?:\s|=)[^]]*)?]#is', '[$1$2][/$1]', $bbcode); |
||
203 | |||
204 | // @todo: find non-singletags without a closing tag and close them (or convert the brackets to entities) |
||
205 | |||
206 | // protect newlines |
||
207 | $bbcode = str_replace(["\r", "\n"], ['', $this->options->placeholder_eol], $bbcode); |
||
0 ignored issues
–
show
Accessing
placeholder_eol on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
208 | // parse the bbcode |
||
209 | $bbcode = $this->parseBBCode($bbcode); |
||
210 | |||
211 | // run the post-parser |
||
212 | if($this->options->postParse){ |
||
0 ignored issues
–
show
Accessing
postParse on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
213 | $bbcode = $this->parserMiddleware->post($bbcode); |
||
214 | } |
||
215 | |||
216 | // replace the newline placeholders |
||
217 | $bbcode = str_replace($this->options->placeholder_eol, $this->outputInterface->getEOL(), $bbcode); |
||
0 ignored issues
–
show
Accessing
placeholder_eol on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
218 | |||
219 | // run the sanitizer/html purifier/whatever as a final step |
||
220 | if($this->options->sanitizeOutput){ |
||
0 ignored issues
–
show
Accessing
sanitizeOutput on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
221 | $bbcode = $this->sanitizerInterface->sanitizeOutput($bbcode); |
||
222 | } |
||
223 | |||
224 | return $bbcode; |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * @param $bbcode |
||
229 | * |
||
230 | * @return string |
||
231 | */ |
||
232 | protected function parseBBCode($bbcode):string{ |
||
233 | static $callback_count = 0; |
||
234 | |||
235 | $callback = false; |
||
236 | |||
237 | if(is_array($bbcode) && count($bbcode) === 4){ |
||
238 | [$match, $tag, $attributes, $content] = $bbcode; |
||
0 ignored issues
–
show
The variable
$match seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case, ![]() The variable
$tag seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case, ![]() The variable
$attributes seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case, ![]() The variable
$content seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case, ![]() |
|||
239 | |||
240 | $tag = strtolower($tag); |
||
0 ignored issues
–
show
The variable
$tag seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case, ![]() |
|||
241 | $attributes = $this->parseAttributes($attributes); |
||
0 ignored issues
–
show
The variable
$attributes seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case, ![]() |
|||
242 | $callback = true; |
||
243 | |||
244 | $callback_count++; |
||
245 | } |
||
246 | else if(is_string($bbcode) && !empty($bbcode)){ |
||
247 | $match = null; |
||
248 | $tag = null; |
||
249 | $attributes = []; |
||
250 | $content = $bbcode; |
||
251 | } |
||
252 | else{ |
||
253 | return ''; |
||
254 | } |
||
255 | |||
256 | if($callback_count < $this->limit && !in_array($tag, $this->noparse , true)){ |
||
257 | $content = preg_replace_callback('#\[(\w+)((?:\s|=)[^]]*)?]((?:[^[]|\[(?!/?\1((?:\s|=)[^]]*)?])|(?R))*)\[/\1]#', __METHOD__, $content); |
||
0 ignored issues
–
show
The variable
$content does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
258 | $e = preg_last_error(); |
||
259 | |||
260 | /** |
||
261 | * 1 - PREG_INTERNAL_ERROR |
||
262 | * 2 - PREG_BACKTRACK_LIMIT_ERROR |
||
263 | * 3 - PREG_RECURSION_LIMIT_ERROR |
||
264 | * 4 - PREG_BAD_UTF8_ERROR |
||
265 | * 5 - PREG_BAD_UTF8_OFFSET_ERROR |
||
266 | * 6 - PREG_JIT_STACKLIMIT_ERROR |
||
267 | */ |
||
268 | if($e !== PREG_NO_ERROR){ |
||
269 | $this->logger->debug('preg_error', ['errno' => $e, '$content' => $content]); |
||
270 | |||
271 | $content = $match ?? '';//$content ?? $bbcode ?? |
||
272 | } |
||
273 | } |
||
274 | |||
275 | if($callback === true && in_array($tag, $this->allowed, true)){ |
||
276 | $content = $this->outputInterface->transform($tag, $attributes, $content, $match, $callback_count); |
||
0 ignored issues
–
show
The variable
$match does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
277 | $callback_count = 0; |
||
278 | } |
||
279 | |||
280 | return $content; |
||
281 | } |
||
282 | |||
283 | /** |
||
284 | * @param string $attributes |
||
285 | * |
||
286 | * @return array |
||
287 | */ |
||
288 | protected function parseAttributes(string $attributes):array{ |
||
289 | $attr = []; |
||
290 | |||
291 | if(empty($attributes)){ |
||
292 | return $attr; |
||
293 | } |
||
294 | |||
295 | // @todo: fix attributes pattern: accept single and double quotes around the value |
||
296 | if(preg_match_all('#(?<name>^|[[a-z]+)\=(["\']?)(?<value>[^"\']*?)\2(?: |$)#i', $attributes, $matches, PREG_SET_ORDER) > 0){ |
||
297 | # print_r(['$attributes' => $attributes, '$matches' => $matches]); |
||
298 | |||
299 | foreach($matches as $attribute){ |
||
300 | $name = empty($attribute['name']) ? $this->options->placeholder_bbtag : strtolower(trim($attribute['name'])); |
||
0 ignored issues
–
show
Accessing
placeholder_bbtag on the interface chillerlan\Settings\SettingsContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
301 | |||
302 | $attr[$name] = trim($attribute['value'], '"\' '); |
||
303 | } |
||
304 | } |
||
305 | |||
306 | $e = preg_last_error(); |
||
307 | |||
308 | if($e !== PREG_NO_ERROR){ |
||
309 | $this->logger->debug('preg_error', ['errno' => $e, '$attributes' => $attributes]); |
||
310 | $attr['__error__'] = $attributes; |
||
311 | } |
||
312 | |||
313 | return $attr; |
||
314 | } |
||
315 | |||
316 | } |
||
317 |
If you access a property on an interface, you most likely code against a concrete implementation of the interface.
Available Fixes
Adding an additional type check:
Changing the type hint: