Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
35 | class Filter { |
||
36 | // REGEX to match a URL |
||
37 | // Some versions of RFC3987 have an appendix B which gives the following regex |
||
38 | // (([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? |
||
|
|||
39 | // This matches far too much while a “precise” regex is several pages long. |
||
40 | // This is a compromise. |
||
41 | const URL_REGEX = '((https?|ftp]):)(//([^\s/?#<>]*))?([^\s?#<>]*)(\?([^\s#<>]*))?(#[^\s?#<>]+)?'; |
||
42 | |||
43 | /** |
||
44 | * Format block-level text such as notes or transcripts, etc. |
||
45 | * |
||
46 | * @param string $text |
||
47 | * @param Tree $WT_TREE |
||
48 | * |
||
49 | * @return string |
||
50 | */ |
||
51 | public static function formatText($text, Tree $WT_TREE) { |
||
59 | |||
60 | /** |
||
61 | * Format a block of text, expanding URLs and XREFs. |
||
62 | * |
||
63 | * @param string $text |
||
64 | * @param Tree tree |
||
65 | * |
||
66 | * @return string |
||
67 | */ |
||
68 | public static function expandUrls($text, Tree $tree) { |
||
69 | // If it looks like a URL, turn it into a markdown autolink. |
||
70 | $text = preg_replace('/' . addcslashes(self::URL_REGEX, '/') . '/', '<$0>', $text); |
||
71 | |||
72 | // Create a minimal commonmark processor - just add support for autolinks. |
||
73 | $environment = new Environment; |
||
74 | $environment->mergeConfig([ |
||
75 | 'renderer' => [ |
||
76 | 'block_separator' => "\n", |
||
77 | 'inner_separator' => "\n", |
||
78 | 'soft_break' => "\n", |
||
79 | ], |
||
80 | 'html_input' => Environment::HTML_INPUT_ESCAPE, |
||
81 | 'allow_unsafe_links' => true, |
||
82 | ]); |
||
83 | |||
84 | $environment |
||
85 | ->addBlockRenderer('League\CommonMark\Block\Element\Document', new DocumentRenderer) |
||
86 | ->addBlockRenderer('League\CommonMark\Block\Element\Paragraph', new ParagraphRenderer) |
||
87 | ->addInlineRenderer('League\CommonMark\Inline\Element\Text', new TextRenderer) |
||
88 | ->addInlineRenderer('League\CommonMark\Inline\Element\Link', new LinkRenderer) |
||
89 | ->addInlineParser(new AutolinkParser); |
||
90 | |||
91 | $environment->addExtension(new CensusTableExtension); |
||
92 | $environment->addExtension(new XrefExtension($tree)); |
||
93 | |||
94 | $converter = new Converter(new DocParser($environment), new HtmlRenderer($environment)); |
||
95 | |||
96 | return $converter->convertToHtml($text); |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * Format a block of text, using "Markdown". |
||
101 | * |
||
102 | * @param string $text |
||
103 | * @param Tree $tree |
||
104 | * |
||
105 | * @return string |
||
106 | */ |
||
107 | public static function markdown($text, Tree $tree) { |
||
108 | $environment = Environment::createCommonMarkEnvironment(); |
||
109 | $environment->mergeConfig(['html_input' => 'escape']); |
||
110 | $environment->addExtension(new TableExtension); |
||
111 | $environment->addExtension(new CensusTableExtension); |
||
112 | $environment->addExtension(new XrefExtension($tree)); |
||
113 | |||
114 | $converter = new Converter(new DocParser($environment), new HtmlRenderer($environment)); |
||
115 | |||
116 | return $converter->convertToHtml($text); |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * Validate INPUT parameters |
||
121 | * |
||
122 | * @param string $source |
||
123 | * @param string $variable |
||
124 | * @param string|null $regexp |
||
125 | * @param string $default |
||
126 | * |
||
127 | * @return string |
||
128 | */ |
||
129 | private static function input($source, $variable, $regexp = null, $default = '') { |
||
130 | if ($regexp) { |
||
131 | return filter_input($source, $variable, FILTER_VALIDATE_REGEXP, [ |
||
132 | 'options' => [ |
||
133 | 'regexp' => '/^(' . $regexp . ')$/u', |
||
134 | 'default' => $default, |
||
135 | ], |
||
136 | ]); |
||
137 | } else { |
||
138 | $tmp = filter_input($source, $variable, FILTER_CALLBACK, [ |
||
139 | 'options' => function ($x) { |
||
140 | return mb_check_encoding($x, 'UTF-8') ? $x : false; |
||
141 | }, |
||
142 | ]); |
||
143 | |||
144 | return ($tmp === null || $tmp === false) ? $default : $tmp; |
||
145 | } |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Validate array INPUT parameters |
||
150 | * |
||
151 | * @param string $source |
||
152 | * @param string $variable |
||
153 | * @param string|null $regexp |
||
154 | * @param string $default |
||
155 | * |
||
156 | * @return string[] |
||
157 | */ |
||
158 | private static function inputArray($source, $variable, $regexp = null, $default = '') { |
||
159 | if ($regexp) { |
||
160 | return filter_input_array($source, [ |
||
161 | $variable => [ |
||
162 | 'flags' => FILTER_REQUIRE_ARRAY, |
||
163 | 'filter' => FILTER_VALIDATE_REGEXP, |
||
164 | 'options' => [ |
||
165 | 'regexp' => '/^(' . $regexp . ')$/u', |
||
166 | 'default' => $default, |
||
167 | ], |
||
168 | ], |
||
169 | ])[$variable] ?: []; |
||
170 | } else { |
||
171 | return filter_input_array($source, [ |
||
172 | $variable => [ |
||
173 | 'flags' => FILTER_REQUIRE_ARRAY, |
||
174 | 'filter' => FILTER_CALLBACK, |
||
175 | 'options' => function ($x) { |
||
176 | return mb_check_encoding($x, 'UTF-8') ? $x : false; |
||
177 | }, |
||
178 | ], |
||
179 | ])[$variable] ?: []; |
||
180 | } |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * Validate GET parameters |
||
185 | * |
||
186 | * @param string $variable |
||
187 | * @param string|null $regexp |
||
188 | * @param string $default |
||
189 | * |
||
190 | * @return string |
||
191 | */ |
||
192 | public static function get($variable, $regexp = null, $default = '') { |
||
195 | |||
196 | /** |
||
197 | * Validate array GET parameters |
||
198 | * |
||
199 | * @param string $variable |
||
200 | * @param string|null $regexp |
||
201 | * @param string $default |
||
202 | * |
||
203 | * @return string[] |
||
204 | */ |
||
205 | public static function getArray($variable, $regexp = null, $default = '') { |
||
208 | |||
209 | /** |
||
210 | * Validate boolean GET parameters |
||
211 | * |
||
212 | * @param string $variable |
||
213 | * |
||
214 | * @return bool |
||
215 | */ |
||
216 | public static function getBool($variable) { |
||
219 | |||
220 | /** |
||
221 | * Validate integer GET parameters |
||
222 | * |
||
223 | * @param string $variable |
||
224 | * @param int $min |
||
225 | * @param int $max |
||
226 | * @param int $default |
||
227 | * |
||
228 | * @return int |
||
229 | */ |
||
230 | View Code Duplication | public static function getInteger($variable, $min = 0, $max = PHP_INT_MAX, $default = 0) { |
|
231 | return filter_input(INPUT_GET, $variable, FILTER_VALIDATE_INT, [ |
||
232 | 'options' => [ |
||
233 | 'min_range' => $min, |
||
234 | 'max_range' => $max, |
||
235 | 'default' => $default, |
||
236 | ], |
||
237 | ]); |
||
238 | } |
||
239 | |||
240 | /** |
||
241 | * Validate URL GET parameters |
||
242 | * |
||
243 | * @param string $variable |
||
244 | * @param string $default |
||
245 | * |
||
246 | * @return string |
||
247 | */ |
||
248 | public static function getUrl($variable, $default = '') { |
||
251 | |||
252 | /** |
||
253 | * Validate POST parameters |
||
254 | * |
||
255 | * @param string $variable |
||
256 | * @param string|null $regexp |
||
257 | * @param string $default |
||
258 | * |
||
259 | * @return string |
||
260 | */ |
||
261 | public static function post($variable, $regexp = null, $default = '') { |
||
264 | |||
265 | /** |
||
266 | * Validate array POST parameters |
||
267 | * |
||
268 | * @param string $variable |
||
269 | * @param string|null $regexp |
||
270 | * @param string $default |
||
271 | * |
||
272 | * @return string[]|string[][] |
||
273 | */ |
||
274 | public static function postArray($variable, $regexp = null, $default = '') { |
||
277 | |||
278 | /** |
||
279 | * Validate boolean POST parameters |
||
280 | * |
||
281 | * @param string $variable |
||
282 | * |
||
283 | * @return bool |
||
284 | */ |
||
285 | public static function postBool($variable) { |
||
288 | |||
289 | /** |
||
290 | * Validate integer POST parameters |
||
291 | * |
||
292 | * @param string $variable |
||
293 | * @param int $min |
||
294 | * @param int $max |
||
295 | * @param int $default |
||
296 | * |
||
297 | * @return int |
||
298 | */ |
||
299 | View Code Duplication | public static function postInteger($variable, $min = 0, $max = PHP_INT_MAX, $default = 0) { |
|
300 | return filter_input(INPUT_POST, $variable, FILTER_VALIDATE_INT, [ |
||
301 | 'options' => [ |
||
302 | 'min_range' => $min, |
||
303 | 'max_range' => $max, |
||
304 | 'default' => $default, |
||
305 | ], |
||
306 | ]); |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * Validate URL GET parameters |
||
311 | * |
||
312 | * @param string $variable |
||
313 | * @param string $default |
||
314 | * |
||
315 | * @return string |
||
316 | */ |
||
317 | public static function postUrl($variable, $default = '') { |
||
320 | |||
321 | /** |
||
322 | * Validate COOKIE parameters |
||
323 | * |
||
324 | * @param string $variable |
||
325 | * @param string|null $regexp |
||
326 | * @param string $default |
||
327 | * |
||
328 | * @return string |
||
329 | */ |
||
330 | public static function cookie($variable, $regexp = null, $default = '') { |
||
333 | |||
334 | /** |
||
335 | * Validate SERVER parameters |
||
336 | * |
||
337 | * @param string $variable |
||
338 | * @param string|null $regexp |
||
339 | * @param string $default |
||
340 | * |
||
341 | * @return string |
||
342 | */ |
||
343 | public static function server($variable, $regexp = null, $default = '') { |
||
344 | // On some servers, variables that are present in $_SERVER cannot be |
||
345 | // found via filter_input(INPUT_SERVER). Instead, they are found via |
||
346 | // filter_input(INPUT_ENV). Since we cannot rely on filter_input(), |
||
347 | // we must use the superglobal directly. |
||
348 | if (array_key_exists($variable, $_SERVER) && ($regexp === null || preg_match('/^(' . $regexp . ')$/', $_SERVER[$variable]))) { |
||
349 | return $_SERVER[$variable]; |
||
350 | } else { |
||
351 | return $default; |
||
352 | } |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * Cross-Site Request Forgery tokens - ensure that the user is submitting |
||
357 | * a form that was generated by the current session. |
||
358 | * |
||
359 | * @return string |
||
360 | */ |
||
361 | public static function getCsrfToken() { |
||
362 | if (!Session::has('CSRF_TOKEN')) { |
||
363 | $charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcedfghijklmnopqrstuvwxyz0123456789'; |
||
364 | $csrf_token = ''; |
||
365 | for ($n = 0; $n < 32; ++$n) { |
||
366 | $csrf_token .= substr($charset, mt_rand(0, 61), 1); |
||
367 | } |
||
368 | Session::put('CSRF_TOKEN', $csrf_token); |
||
369 | } |
||
370 | |||
371 | return Session::get('CSRF_TOKEN'); |
||
372 | } |
||
373 | |||
374 | /** |
||
375 | * Generate an <input> element - to protect the current form from CSRF attacks. |
||
376 | * |
||
377 | * @return string |
||
378 | */ |
||
379 | public static function getCsrf() { |
||
382 | |||
383 | /** |
||
384 | * Check that the POST request contains the CSRF token generated above. |
||
385 | * |
||
386 | * @return bool |
||
387 | */ |
||
388 | public static function checkCsrf() { |
||
399 | } |
||
400 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.