Mercurial > hg > isophonics-drupal-site
comparison vendor/squizlabs/php_codesniffer/src/Util/Common.php @ 17:129ea1e6d783
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:21:36 +0000 |
parents | |
children | af1871eacc83 |
comparison
equal
deleted
inserted
replaced
16:c2387f117808 | 17:129ea1e6d783 |
---|---|
1 <?php | |
2 /** | |
3 * Basic util functions. | |
4 * | |
5 * @author Greg Sherwood <gsherwood@squiz.net> | |
6 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) | |
7 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence | |
8 */ | |
9 | |
10 namespace PHP_CodeSniffer\Util; | |
11 | |
12 class Common | |
13 { | |
14 | |
15 /** | |
16 * An array of variable types for param/var we will check. | |
17 * | |
18 * @var string[] | |
19 */ | |
20 public static $allowedTypes = [ | |
21 'array', | |
22 'boolean', | |
23 'float', | |
24 'integer', | |
25 'mixed', | |
26 'object', | |
27 'string', | |
28 'resource', | |
29 'callable', | |
30 ]; | |
31 | |
32 | |
33 /** | |
34 * Return TRUE if the path is a PHAR file. | |
35 * | |
36 * @param string $path The path to use. | |
37 * | |
38 * @return mixed | |
39 */ | |
40 public static function isPharFile($path) | |
41 { | |
42 if (strpos($path, 'phar://') === 0) { | |
43 return true; | |
44 } | |
45 | |
46 return false; | |
47 | |
48 }//end isPharFile() | |
49 | |
50 | |
51 /** | |
52 * CodeSniffer alternative for realpath. | |
53 * | |
54 * Allows for PHAR support. | |
55 * | |
56 * @param string $path The path to use. | |
57 * | |
58 * @return mixed | |
59 */ | |
60 public static function realpath($path) | |
61 { | |
62 // Support the path replacement of ~ with the user's home directory. | |
63 if (substr($path, 0, 2) === '~/') { | |
64 $homeDir = getenv('HOME'); | |
65 if ($homeDir !== false) { | |
66 $path = $homeDir.substr($path, 1); | |
67 } | |
68 } | |
69 | |
70 // Check for process substitution. | |
71 if (strpos($path, '/dev/fd') === 0) { | |
72 return str_replace('/dev/fd', 'php://fd', $path); | |
73 } | |
74 | |
75 // No extra work needed if this is not a phar file. | |
76 if (self::isPharFile($path) === false) { | |
77 return realpath($path); | |
78 } | |
79 | |
80 // Before trying to break down the file path, | |
81 // check if it exists first because it will mostly not | |
82 // change after running the below code. | |
83 if (file_exists($path) === true) { | |
84 return $path; | |
85 } | |
86 | |
87 $phar = \Phar::running(false); | |
88 $extra = str_replace('phar://'.$phar, '', $path); | |
89 $path = realpath($phar); | |
90 if ($path === false) { | |
91 return false; | |
92 } | |
93 | |
94 $path = 'phar://'.$path.$extra; | |
95 if (file_exists($path) === true) { | |
96 return $path; | |
97 } | |
98 | |
99 return false; | |
100 | |
101 }//end realpath() | |
102 | |
103 | |
104 /** | |
105 * Removes a base path from the front of a file path. | |
106 * | |
107 * @param string $path The path of the file. | |
108 * @param string $basepath The base path to remove. This should not end | |
109 * with a directory separator. | |
110 * | |
111 * @return string | |
112 */ | |
113 public static function stripBasepath($path, $basepath) | |
114 { | |
115 if (empty($basepath) === true) { | |
116 return $path; | |
117 } | |
118 | |
119 $basepathLen = strlen($basepath); | |
120 if (substr($path, 0, $basepathLen) === $basepath) { | |
121 $path = substr($path, $basepathLen); | |
122 } | |
123 | |
124 $path = ltrim($path, DIRECTORY_SEPARATOR); | |
125 if ($path === '') { | |
126 $path = '.'; | |
127 } | |
128 | |
129 return $path; | |
130 | |
131 }//end stripBasepath() | |
132 | |
133 | |
134 /** | |
135 * Detects the EOL character being used in a string. | |
136 * | |
137 * @param string $contents The contents to check. | |
138 * | |
139 * @return string | |
140 */ | |
141 public static function detectLineEndings($contents) | |
142 { | |
143 if (preg_match("/\r\n?|\n/", $contents, $matches) !== 1) { | |
144 // Assume there are no newlines. | |
145 $eolChar = "\n"; | |
146 } else { | |
147 $eolChar = $matches[0]; | |
148 } | |
149 | |
150 return $eolChar; | |
151 | |
152 }//end detectLineEndings() | |
153 | |
154 | |
155 /** | |
156 * Check if STDIN is a TTY. | |
157 * | |
158 * @return boolean | |
159 */ | |
160 public static function isStdinATTY() | |
161 { | |
162 // The check is slow (especially calling `tty`) so we static | |
163 // cache the result. | |
164 static $isTTY = null; | |
165 | |
166 if ($isTTY !== null) { | |
167 return $isTTY; | |
168 } | |
169 | |
170 if (defined('STDIN') === false) { | |
171 return false; | |
172 } | |
173 | |
174 // If PHP has the POSIX extensions we will use them. | |
175 if (function_exists('posix_isatty') === true) { | |
176 $isTTY = (posix_isatty(STDIN) === true); | |
177 return $isTTY; | |
178 } | |
179 | |
180 // Next try is detecting whether we have `tty` installed and use that. | |
181 if (defined('PHP_WINDOWS_VERSION_PLATFORM') === true) { | |
182 $devnull = 'NUL'; | |
183 $which = 'where'; | |
184 } else { | |
185 $devnull = '/dev/null'; | |
186 $which = 'which'; | |
187 } | |
188 | |
189 $tty = trim(shell_exec("$which tty 2> $devnull")); | |
190 if (empty($tty) === false) { | |
191 exec("tty -s 2> $devnull", $output, $returnValue); | |
192 $isTTY = ($returnValue === 0); | |
193 return $isTTY; | |
194 } | |
195 | |
196 // Finally we will use fstat. The solution borrowed from | |
197 // https://stackoverflow.com/questions/11327367/detect-if-a-php-script-is-being-run-interactively-or-not | |
198 // This doesn't work on Mingw/Cygwin/... using Mintty but they | |
199 // have `tty` installed. | |
200 $type = [ | |
201 'S_IFMT' => 0170000, | |
202 'S_IFIFO' => 0010000, | |
203 ]; | |
204 | |
205 $stat = fstat(STDIN); | |
206 $mode = ($stat['mode'] & $type['S_IFMT']); | |
207 $isTTY = ($mode !== $type['S_IFIFO']); | |
208 | |
209 return $isTTY; | |
210 | |
211 }//end isStdinATTY() | |
212 | |
213 | |
214 /** | |
215 * Prepares token content for output to screen. | |
216 * | |
217 * Replaces invisible characters so they are visible. On non-Windows | |
218 * OSes it will also colour the invisible characters. | |
219 * | |
220 * @param string $content The content to prepare. | |
221 * @param string[] $exclude A list of characters to leave invisible. | |
222 * Can contain \r, \n, \t and a space. | |
223 * | |
224 * @return string | |
225 */ | |
226 public static function prepareForOutput($content, $exclude=[]) | |
227 { | |
228 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { | |
229 if (in_array("\r", $exclude) === false) { | |
230 $content = str_replace("\r", '\r', $content); | |
231 } | |
232 | |
233 if (in_array("\n", $exclude) === false) { | |
234 $content = str_replace("\n", '\n', $content); | |
235 } | |
236 | |
237 if (in_array("\t", $exclude) === false) { | |
238 $content = str_replace("\t", '\t', $content); | |
239 } | |
240 } else { | |
241 if (in_array("\r", $exclude) === false) { | |
242 $content = str_replace("\r", "\033[30;1m\\r\033[0m", $content); | |
243 } | |
244 | |
245 if (in_array("\n", $exclude) === false) { | |
246 $content = str_replace("\n", "\033[30;1m\\n\033[0m", $content); | |
247 } | |
248 | |
249 if (in_array("\t", $exclude) === false) { | |
250 $content = str_replace("\t", "\033[30;1m\\t\033[0m", $content); | |
251 } | |
252 | |
253 if (in_array(' ', $exclude) === false) { | |
254 $content = str_replace(' ', "\033[30;1m·\033[0m", $content); | |
255 } | |
256 }//end if | |
257 | |
258 return $content; | |
259 | |
260 }//end prepareForOutput() | |
261 | |
262 | |
263 /** | |
264 * Returns true if the specified string is in the camel caps format. | |
265 * | |
266 * @param string $string The string the verify. | |
267 * @param boolean $classFormat If true, check to see if the string is in the | |
268 * class format. Class format strings must start | |
269 * with a capital letter and contain no | |
270 * underscores. | |
271 * @param boolean $public If true, the first character in the string | |
272 * must be an a-z character. If false, the | |
273 * character must be an underscore. This | |
274 * argument is only applicable if $classFormat | |
275 * is false. | |
276 * @param boolean $strict If true, the string must not have two capital | |
277 * letters next to each other. If false, a | |
278 * relaxed camel caps policy is used to allow | |
279 * for acronyms. | |
280 * | |
281 * @return boolean | |
282 */ | |
283 public static function isCamelCaps( | |
284 $string, | |
285 $classFormat=false, | |
286 $public=true, | |
287 $strict=true | |
288 ) { | |
289 // Check the first character first. | |
290 if ($classFormat === false) { | |
291 $legalFirstChar = ''; | |
292 if ($public === false) { | |
293 $legalFirstChar = '[_]'; | |
294 } | |
295 | |
296 if ($strict === false) { | |
297 // Can either start with a lowercase letter, or multiple uppercase | |
298 // in a row, representing an acronym. | |
299 $legalFirstChar .= '([A-Z]{2,}|[a-z])'; | |
300 } else { | |
301 $legalFirstChar .= '[a-z]'; | |
302 } | |
303 } else { | |
304 $legalFirstChar = '[A-Z]'; | |
305 } | |
306 | |
307 if (preg_match("/^$legalFirstChar/", $string) === 0) { | |
308 return false; | |
309 } | |
310 | |
311 // Check that the name only contains legal characters. | |
312 $legalChars = 'a-zA-Z0-9'; | |
313 if (preg_match("|[^$legalChars]|", substr($string, 1)) > 0) { | |
314 return false; | |
315 } | |
316 | |
317 if ($strict === true) { | |
318 // Check that there are not two capital letters next to each other. | |
319 $length = strlen($string); | |
320 $lastCharWasCaps = $classFormat; | |
321 | |
322 for ($i = 1; $i < $length; $i++) { | |
323 $ascii = ord($string{$i}); | |
324 if ($ascii >= 48 && $ascii <= 57) { | |
325 // The character is a number, so it cant be a capital. | |
326 $isCaps = false; | |
327 } else { | |
328 if (strtoupper($string{$i}) === $string{$i}) { | |
329 $isCaps = true; | |
330 } else { | |
331 $isCaps = false; | |
332 } | |
333 } | |
334 | |
335 if ($isCaps === true && $lastCharWasCaps === true) { | |
336 return false; | |
337 } | |
338 | |
339 $lastCharWasCaps = $isCaps; | |
340 } | |
341 }//end if | |
342 | |
343 return true; | |
344 | |
345 }//end isCamelCaps() | |
346 | |
347 | |
348 /** | |
349 * Returns true if the specified string is in the underscore caps format. | |
350 * | |
351 * @param string $string The string to verify. | |
352 * | |
353 * @return boolean | |
354 */ | |
355 public static function isUnderscoreName($string) | |
356 { | |
357 // If there are space in the name, it can't be valid. | |
358 if (strpos($string, ' ') !== false) { | |
359 return false; | |
360 } | |
361 | |
362 $validName = true; | |
363 $nameBits = explode('_', $string); | |
364 | |
365 if (preg_match('|^[A-Z]|', $string) === 0) { | |
366 // Name does not begin with a capital letter. | |
367 $validName = false; | |
368 } else { | |
369 foreach ($nameBits as $bit) { | |
370 if ($bit === '') { | |
371 continue; | |
372 } | |
373 | |
374 if ($bit{0} !== strtoupper($bit{0})) { | |
375 $validName = false; | |
376 break; | |
377 } | |
378 } | |
379 } | |
380 | |
381 return $validName; | |
382 | |
383 }//end isUnderscoreName() | |
384 | |
385 | |
386 /** | |
387 * Returns a valid variable type for param/var tag. | |
388 * | |
389 * If type is not one of the standard type, it must be a custom type. | |
390 * Returns the correct type name suggestion if type name is invalid. | |
391 * | |
392 * @param string $varType The variable type to process. | |
393 * | |
394 * @return string | |
395 */ | |
396 public static function suggestType($varType) | |
397 { | |
398 if ($varType === '') { | |
399 return ''; | |
400 } | |
401 | |
402 if (in_array($varType, self::$allowedTypes) === true) { | |
403 return $varType; | |
404 } else { | |
405 $lowerVarType = strtolower($varType); | |
406 switch ($lowerVarType) { | |
407 case 'bool': | |
408 case 'boolean': | |
409 return 'boolean'; | |
410 case 'double': | |
411 case 'real': | |
412 case 'float': | |
413 return 'float'; | |
414 case 'int': | |
415 case 'integer': | |
416 return 'integer'; | |
417 case 'array()': | |
418 case 'array': | |
419 return 'array'; | |
420 }//end switch | |
421 | |
422 if (strpos($lowerVarType, 'array(') !== false) { | |
423 // Valid array declaration: | |
424 // array, array(type), array(type1 => type2). | |
425 $matches = []; | |
426 $pattern = '/^array\(\s*([^\s^=^>]*)(\s*=>\s*(.*))?\s*\)/i'; | |
427 if (preg_match($pattern, $varType, $matches) !== 0) { | |
428 $type1 = ''; | |
429 if (isset($matches[1]) === true) { | |
430 $type1 = $matches[1]; | |
431 } | |
432 | |
433 $type2 = ''; | |
434 if (isset($matches[3]) === true) { | |
435 $type2 = $matches[3]; | |
436 } | |
437 | |
438 $type1 = self::suggestType($type1); | |
439 $type2 = self::suggestType($type2); | |
440 if ($type2 !== '') { | |
441 $type2 = ' => '.$type2; | |
442 } | |
443 | |
444 return "array($type1$type2)"; | |
445 } else { | |
446 return 'array'; | |
447 }//end if | |
448 } else if (in_array($lowerVarType, self::$allowedTypes) === true) { | |
449 // A valid type, but not lower cased. | |
450 return $lowerVarType; | |
451 } else { | |
452 // Must be a custom type name. | |
453 return $varType; | |
454 }//end if | |
455 }//end if | |
456 | |
457 }//end suggestType() | |
458 | |
459 | |
460 /** | |
461 * Given a sniff class name, returns the code for the sniff. | |
462 * | |
463 * @param string $sniffClass The fully qualified sniff class name. | |
464 * | |
465 * @return string | |
466 */ | |
467 public static function getSniffCode($sniffClass) | |
468 { | |
469 $parts = explode('\\', $sniffClass); | |
470 $sniff = array_pop($parts); | |
471 | |
472 if (substr($sniff, -5) === 'Sniff') { | |
473 // Sniff class name. | |
474 $sniff = substr($sniff, 0, -5); | |
475 } else { | |
476 // Unit test class name. | |
477 $sniff = substr($sniff, 0, -8); | |
478 } | |
479 | |
480 $category = array_pop($parts); | |
481 $sniffDir = array_pop($parts); | |
482 $standard = array_pop($parts); | |
483 $code = $standard.'.'.$category.'.'.$sniff; | |
484 return $code; | |
485 | |
486 }//end getSniffCode() | |
487 | |
488 | |
489 /** | |
490 * Removes project-specific information from a sniff class name. | |
491 * | |
492 * @param string $sniffClass The fully qualified sniff class name. | |
493 * | |
494 * @return string | |
495 */ | |
496 public static function cleanSniffClass($sniffClass) | |
497 { | |
498 $newName = strtolower($sniffClass); | |
499 | |
500 $sniffPos = strrpos($newName, '\sniffs\\'); | |
501 if ($sniffPos === false) { | |
502 // Nothing we can do as it isn't in a known format. | |
503 return $newName; | |
504 } | |
505 | |
506 $end = (strlen($newName) - $sniffPos + 1); | |
507 $start = strrpos($newName, '\\', ($end * -1)); | |
508 | |
509 if ($start === false) { | |
510 // Nothing needs to be cleaned. | |
511 return $newName; | |
512 } | |
513 | |
514 $newName = substr($newName, ($start + 1)); | |
515 return $newName; | |
516 | |
517 }//end cleanSniffClass() | |
518 | |
519 | |
520 }//end class |