1<?php 2/** 3 * A class to process command line phpcs scripts. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer 9 * @author Greg Sherwood <gsherwood@squiz.net> 10 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 11 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 12 * @link http://pear.php.net/package/PHP_CodeSniffer 13 */ 14 15error_reporting(E_ALL | E_STRICT); 16 17// Make sure version id constant is available. 18if (defined('PHP_VERSION_ID') === false) { 19 $version = explode('.', PHP_VERSION); 20 define('PHP_VERSION_ID', (int) (($version[0] * 10000) + ($version[1] * 100) + $version[2])); 21 unset($version); 22} 23 24// Make sure that we autoload all dependencies if running via Composer. 25if (PHP_VERSION_ID >= 50302) { 26 if (file_exists($a = dirname(__FILE__).'/../../../autoload.php') === true) { 27 include_once $a; 28 } else if (file_exists($a = dirname(__FILE__).'/../vendor/autoload.php') === true) { 29 include_once $a; 30 } 31} 32 33if (file_exists($a = dirname(__FILE__).'/../CodeSniffer.php') === true) { 34 // Running from a git clone. 35 include_once $a; 36} else { 37 // PEAR installed. 38 include_once 'PHP/CodeSniffer.php'; 39} 40 41/** 42 * A class to process command line phpcs scripts. 43 * 44 * @category PHP 45 * @package PHP_CodeSniffer 46 * @author Greg Sherwood <gsherwood@squiz.net> 47 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 48 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 49 * @version Release: @package_version@ 50 * @link http://pear.php.net/package/PHP_CodeSniffer 51 */ 52class PHP_CodeSniffer_CLI 53{ 54 55 /** 56 * An array of all values specified on the command line. 57 * 58 * @var array 59 */ 60 protected $values = array(); 61 62 /** 63 * The minimum severity level errors must have to be displayed. 64 * 65 * @var bool 66 */ 67 public $errorSeverity = 0; 68 69 /** 70 * The minimum severity level warnings must have to be displayed. 71 * 72 * @var bool 73 */ 74 public $warningSeverity = 0; 75 76 /** 77 * Whether or not to kill the process when an unknown command line arg is found. 78 * 79 * If FALSE, arguments that are not command line options or file/directory paths 80 * will be ignored and execution will continue. 81 * 82 * @var bool 83 */ 84 public $dieOnUnknownArg = true; 85 86 /** 87 * An array of the current command line arguments we are processing. 88 * 89 * @var array 90 */ 91 private $_cliArgs = array(); 92 93 94 /** 95 * Run the PHPCS script. 96 * 97 * @return array 98 */ 99 public function runphpcs() 100 { 101 if (defined('PHP_CODESNIFFER_CBF') === false) { 102 define('PHP_CODESNIFFER_CBF', false); 103 } 104 105 if (is_file(dirname(__FILE__).'/../CodeSniffer/Reporting.php') === true) { 106 include_once dirname(__FILE__).'/../CodeSniffer/Reporting.php'; 107 } else { 108 include_once 'PHP/CodeSniffer/Reporting.php'; 109 } 110 111 PHP_CodeSniffer_Reporting::startTiming(); 112 $this->checkRequirements(); 113 $numErrors = $this->process(); 114 if ($numErrors === 0) { 115 exit(0); 116 } else { 117 exit(1); 118 } 119 120 }//end runphpcs() 121 122 123 /** 124 * Run the PHPCBF script. 125 * 126 * @return array 127 */ 128 public function runphpcbf() 129 { 130 if (defined('PHP_CODESNIFFER_CBF') === false) { 131 define('PHP_CODESNIFFER_CBF', true); 132 } 133 134 if (is_file(dirname(__FILE__).'/../CodeSniffer/Reporting.php') === true) { 135 include_once dirname(__FILE__).'/../CodeSniffer/Reporting.php'; 136 } else { 137 include_once 'PHP/CodeSniffer/Reporting.php'; 138 } 139 140 PHP_CodeSniffer_Reporting::startTiming(); 141 $this->checkRequirements(); 142 143 $this->dieOnUnknownArg = false; 144 145 // Override some of the command line settings that might break the fixes. 146 $cliValues = $this->getCommandLineValues(); 147 $cliValues['verbosity'] = 0; 148 $cliValues['showProgress'] = false; 149 $cliValues['generator'] = ''; 150 $cliValues['explain'] = false; 151 $cliValues['interactive'] = false; 152 $cliValues['showSources'] = false; 153 $cliValues['reportFile'] = null; 154 $cliValues['reports'] = array(); 155 156 $suffix = ''; 157 if (isset($cliValues['suffix']) === true) { 158 $suffix = $cliValues['suffix']; 159 } 160 161 $allowPatch = true; 162 if (isset($cliValues['no-patch']) === true || empty($cliValues['files']) === true) { 163 // They either asked for this, 164 // or they are using STDIN, which can't use diff. 165 $allowPatch = false; 166 } 167 168 if ($suffix === '' && $allowPatch === true) { 169 // Using the diff/patch tools. 170 $diffFile = getcwd().'/phpcbf-fixed.diff'; 171 $cliValues['reports'] = array('diff' => $diffFile); 172 if (file_exists($diffFile) === true) { 173 unlink($diffFile); 174 } 175 } else { 176 // Replace the file without the patch command 177 // or writing to a file with a new suffix. 178 $cliValues['reports'] = array('cbf' => null); 179 $cliValues['phpcbf-suffix'] = $suffix; 180 } 181 182 $numErrors = $this->process($cliValues); 183 184 if ($suffix === '' && $allowPatch === true) { 185 if (file_exists($diffFile) === false) { 186 // Nothing to fix. 187 if ($numErrors === 0) { 188 // And no errors reported. 189 $exit = 0; 190 } else { 191 // Errors we can't fix. 192 $exit = 2; 193 } 194 } else { 195 if (filesize($diffFile) < 10) { 196 // Empty or bad diff file. 197 if ($numErrors === 0) { 198 // And no errors reported. 199 $exit = 0; 200 } else { 201 // Errors we can't fix. 202 $exit = 2; 203 } 204 } else { 205 $cmd = "patch -p0 -ui \"$diffFile\""; 206 $output = array(); 207 $retVal = null; 208 exec($cmd, $output, $retVal); 209 210 if ($retVal === 0) { 211 // Everything went well. 212 $filesPatched = count($output); 213 echo "Patched $filesPatched file"; 214 if ($filesPatched > 1) { 215 echo 's'; 216 } 217 218 echo PHP_EOL; 219 $exit = 1; 220 } else { 221 print_r($output); 222 echo "Returned: $retVal".PHP_EOL; 223 $exit = 3; 224 } 225 }//end if 226 227 unlink($diffFile); 228 }//end if 229 } else { 230 // File are being patched manually, so we can't tell 231 // how many errors were fixed. 232 $exit = 1; 233 }//end if 234 235 if ($exit === 0) { 236 echo 'No fixable errors were found'.PHP_EOL; 237 } else if ($exit === 2) { 238 echo 'PHPCBF could not fix all the errors found'.PHP_EOL; 239 } 240 241 PHP_CodeSniffer_Reporting::printRunTime(); 242 exit($exit); 243 244 }//end runphpcbf() 245 246 247 /** 248 * Exits if the minimum requirements of PHP_CodSniffer are not met. 249 * 250 * @return array 251 */ 252 public function checkRequirements() 253 { 254 // Check the PHP version. 255 if (PHP_VERSION_ID < 50102) { 256 echo 'ERROR: PHP_CodeSniffer requires PHP version 5.1.2 or greater.'.PHP_EOL; 257 exit(2); 258 } 259 260 if (extension_loaded('tokenizer') === false) { 261 echo 'ERROR: PHP_CodeSniffer requires the tokenizer extension to be enabled.'.PHP_EOL; 262 exit(2); 263 } 264 265 }//end checkRequirements() 266 267 268 /** 269 * Get a list of default values for all possible command line arguments. 270 * 271 * @return array 272 */ 273 public function getDefaults() 274 { 275 if (defined('PHP_CODESNIFFER_IN_TESTS') === true) { 276 return array(); 277 } 278 279 // The default values for config settings. 280 $defaults['files'] = array(); 281 $defaults['standard'] = null; 282 $defaults['verbosity'] = 0; 283 $defaults['interactive'] = false; 284 $defaults['colors'] = false; 285 $defaults['explain'] = false; 286 $defaults['local'] = false; 287 $defaults['showSources'] = false; 288 $defaults['extensions'] = array(); 289 $defaults['sniffs'] = array(); 290 $defaults['exclude'] = array(); 291 $defaults['ignored'] = array(); 292 $defaults['reportFile'] = null; 293 $defaults['generator'] = ''; 294 $defaults['reports'] = array(); 295 $defaults['bootstrap'] = array(); 296 $defaults['errorSeverity'] = null; 297 $defaults['warningSeverity'] = null; 298 $defaults['stdin'] = null; 299 $defaults['stdinPath'] = ''; 300 301 $reportFormat = PHP_CodeSniffer::getConfigData('report_format'); 302 if ($reportFormat !== null) { 303 $defaults['reports'][$reportFormat] = null; 304 } 305 306 $tabWidth = PHP_CodeSniffer::getConfigData('tab_width'); 307 if ($tabWidth === null) { 308 $defaults['tabWidth'] = 0; 309 } else { 310 $defaults['tabWidth'] = (int) $tabWidth; 311 } 312 313 $encoding = PHP_CodeSniffer::getConfigData('encoding'); 314 if ($encoding === null) { 315 $defaults['encoding'] = 'iso-8859-1'; 316 } else { 317 $defaults['encoding'] = strtolower($encoding); 318 } 319 320 $severity = PHP_CodeSniffer::getConfigData('severity'); 321 if ($severity !== null) { 322 $defaults['errorSeverity'] = (int) $severity; 323 $defaults['warningSeverity'] = (int) $severity; 324 } 325 326 $severity = PHP_CodeSniffer::getConfigData('error_severity'); 327 if ($severity !== null) { 328 $defaults['errorSeverity'] = (int) $severity; 329 } 330 331 $severity = PHP_CodeSniffer::getConfigData('warning_severity'); 332 if ($severity !== null) { 333 $defaults['warningSeverity'] = (int) $severity; 334 } 335 336 $showWarnings = PHP_CodeSniffer::getConfigData('show_warnings'); 337 if ($showWarnings !== null) { 338 $showWarnings = (bool) $showWarnings; 339 if ($showWarnings === false) { 340 $defaults['warningSeverity'] = 0; 341 } 342 } 343 344 $reportWidth = PHP_CodeSniffer::getConfigData('report_width'); 345 if ($reportWidth !== null) { 346 $defaults['reportWidth'] = $this->_validateReportWidth($reportWidth); 347 } else { 348 // Use function defaults. 349 $defaults['reportWidth'] = null; 350 } 351 352 $showProgress = PHP_CodeSniffer::getConfigData('show_progress'); 353 if ($showProgress === null) { 354 $defaults['showProgress'] = false; 355 } else { 356 $defaults['showProgress'] = (bool) $showProgress; 357 } 358 359 $quiet = PHP_CodeSniffer::getConfigData('quiet'); 360 if ($quiet === null) { 361 $defaults['quiet'] = false; 362 } else { 363 $defaults['quiet'] = (bool) $quiet; 364 } 365 366 $colors = PHP_CodeSniffer::getConfigData('colors'); 367 if ($colors === null) { 368 $defaults['colors'] = false; 369 } else { 370 $defaults['colors'] = (bool) $colors; 371 } 372 373 if (PHP_CodeSniffer::isPharFile(dirname(dirname(__FILE__))) === true) { 374 // If this is a phar file, check for the standard in the config. 375 $standard = PHP_CodeSniffer::getConfigData('standard'); 376 if ($standard !== null) { 377 $defaults['standard'] = $standard; 378 } 379 } 380 381 return $defaults; 382 383 }//end getDefaults() 384 385 386 /** 387 * Gets the processed command line values. 388 * 389 * If the values have not yet been set, the values will be sourced 390 * from the command line arguments. 391 * 392 * @return array 393 */ 394 public function getCommandLineValues() 395 { 396 if (empty($this->values) === false) { 397 return $this->values; 398 } 399 400 $args = $_SERVER['argv']; 401 array_shift($args); 402 403 $this->setCommandLineValues($args); 404 405 // Check for content on STDIN. 406 $handle = fopen('php://stdin', 'r'); 407 if (stream_set_blocking($handle, false) === true) { 408 $fileContents = ''; 409 while (($line = fgets($handle)) !== false) { 410 $fileContents .= $line; 411 usleep(10); 412 } 413 414 stream_set_blocking($handle, true); 415 fclose($handle); 416 if (trim($fileContents) !== '') { 417 $this->values['stdin'] = $fileContents; 418 } 419 } 420 421 return $this->values; 422 423 }//end getCommandLineValues() 424 425 426 /** 427 * Set the command line values. 428 * 429 * @param array $args An array of command line arguments to process. 430 * 431 * @return void 432 */ 433 public function setCommandLineValues($args) 434 { 435 if (defined('PHP_CODESNIFFER_IN_TESTS') === true) { 436 $this->values = array( 437 'stdin' => null, 438 'quiet' => true, 439 ); 440 } else if (empty($this->values) === true) { 441 $this->values = $this->getDefaults(); 442 } 443 444 $this->_cliArgs = $args; 445 $numArgs = count($args); 446 447 for ($i = 0; $i < $numArgs; $i++) { 448 $arg = $this->_cliArgs[$i]; 449 if ($arg === '') { 450 continue; 451 } 452 453 if ($arg{0} === '-') { 454 if ($arg === '-' || $arg === '--') { 455 // Empty argument, ignore it. 456 continue; 457 } 458 459 if ($arg{1} === '-') { 460 $this->processLongArgument(substr($arg, 2), $i); 461 } else { 462 $switches = str_split($arg); 463 foreach ($switches as $switch) { 464 if ($switch === '-') { 465 continue; 466 } 467 468 $this->processShortArgument($switch, $i); 469 } 470 } 471 } else { 472 $this->processUnknownArgument($arg, $i); 473 }//end if 474 }//end for 475 476 }//end setCommandLineValues() 477 478 479 /** 480 * Processes a short (-e) command line argument. 481 * 482 * @param string $arg The command line argument. 483 * @param int $pos The position of the argument on the command line. 484 * 485 * @return void 486 */ 487 public function processShortArgument($arg, $pos) 488 { 489 switch ($arg) { 490 case 'h': 491 case '?': 492 $this->printUsage(); 493 exit(0); 494 case 'i' : 495 $this->printInstalledStandards(); 496 exit(0); 497 case 'v' : 498 if ($this->values['quiet'] === true) { 499 // Ignore when quiet mode is enabled. 500 break; 501 } 502 503 if (isset($this->values['verbosity']) === false) { 504 $this->values['verbosity'] = 1; 505 } else { 506 $this->values['verbosity']++; 507 } 508 break; 509 case 'l' : 510 $this->values['local'] = true; 511 break; 512 case 's' : 513 $this->values['showSources'] = true; 514 break; 515 case 'a' : 516 $this->values['interactive'] = true; 517 break; 518 case 'e': 519 $this->values['explain'] = true; 520 break; 521 case 'p' : 522 if ($this->values['quiet'] === true) { 523 // Ignore when quiet mode is enabled. 524 break; 525 } 526 527 $this->values['showProgress'] = true; 528 break; 529 case 'q' : 530 // Quiet mode disables a few other settings as well. 531 $this->values['quiet'] = true; 532 $this->values['showProgress'] = false; 533 $this->values['verbosity'] = 0; 534 break; 535 case 'd' : 536 $ini = explode('=', $this->_cliArgs[($pos + 1)]); 537 $this->_cliArgs[($pos + 1)] = ''; 538 if (isset($ini[1]) === true) { 539 ini_set($ini[0], $ini[1]); 540 } else { 541 ini_set($ini[0], true); 542 } 543 break; 544 case 'n' : 545 $this->values['warningSeverity'] = 0; 546 break; 547 case 'w' : 548 $this->values['warningSeverity'] = null; 549 break; 550 default: 551 if ($this->dieOnUnknownArg === false) { 552 $this->values[$arg] = $arg; 553 } else { 554 $this->processUnknownArgument('-'.$arg, $pos); 555 } 556 }//end switch 557 558 }//end processShortArgument() 559 560 561 /** 562 * Processes a long (--example) command line argument. 563 * 564 * @param string $arg The command line argument. 565 * @param int $pos The position of the argument on the command line. 566 * 567 * @return void 568 */ 569 public function processLongArgument($arg, $pos) 570 { 571 switch ($arg) { 572 case 'help': 573 $this->printUsage(); 574 exit(0); 575 case 'version': 576 echo 'PHP_CodeSniffer version '.PHP_CodeSniffer::VERSION.' ('.PHP_CodeSniffer::STABILITY.') '; 577 echo 'by Squiz (http://www.squiz.net)'.PHP_EOL; 578 exit(0); 579 case 'colors': 580 $this->values['colors'] = true; 581 break; 582 case 'no-colors': 583 $this->values['colors'] = false; 584 break; 585 case 'config-set': 586 if (isset($this->_cliArgs[($pos + 1)]) === false 587 || isset($this->_cliArgs[($pos + 2)]) === false 588 ) { 589 echo 'ERROR: Setting a config option requires a name and value'.PHP_EOL.PHP_EOL; 590 $this->printUsage(); 591 exit(0); 592 } 593 594 $key = $this->_cliArgs[($pos + 1)]; 595 $value = $this->_cliArgs[($pos + 2)]; 596 $current = PHP_CodeSniffer::getConfigData($key); 597 598 try { 599 PHP_CodeSniffer::setConfigData($key, $value); 600 } catch (Exception $e) { 601 echo $e->getMessage().PHP_EOL; 602 exit(2); 603 } 604 605 if ($current === null) { 606 echo "Config value \"$key\" added successfully".PHP_EOL; 607 } else { 608 echo "Config value \"$key\" updated successfully; old value was \"$current\"".PHP_EOL; 609 } 610 exit(0); 611 case 'config-delete': 612 if (isset($this->_cliArgs[($pos + 1)]) === false) { 613 echo 'ERROR: Deleting a config option requires the name of the option'.PHP_EOL.PHP_EOL; 614 $this->printUsage(); 615 exit(0); 616 } 617 618 $key = $this->_cliArgs[($pos + 1)]; 619 $current = PHP_CodeSniffer::getConfigData($key); 620 if ($current === null) { 621 echo "Config value \"$key\" has not been set".PHP_EOL; 622 } else { 623 try { 624 PHP_CodeSniffer::setConfigData($key, null); 625 } catch (Exception $e) { 626 echo $e->getMessage().PHP_EOL; 627 exit(2); 628 } 629 630 echo "Config value \"$key\" removed successfully; old value was \"$current\"".PHP_EOL; 631 } 632 exit(0); 633 case 'config-show': 634 $data = PHP_CodeSniffer::getAllConfigData(); 635 $this->printConfigData($data); 636 exit(0); 637 case 'runtime-set': 638 if (isset($this->_cliArgs[($pos + 1)]) === false 639 || isset($this->_cliArgs[($pos + 2)]) === false 640 ) { 641 echo 'ERROR: Setting a runtime config option requires a name and value'.PHP_EOL.PHP_EOL; 642 $this->printUsage(); 643 exit(0); 644 } 645 646 $key = $this->_cliArgs[($pos + 1)]; 647 $value = $this->_cliArgs[($pos + 2)]; 648 $this->_cliArgs[($pos + 1)] = ''; 649 $this->_cliArgs[($pos + 2)] = ''; 650 PHP_CodeSniffer::setConfigData($key, $value, true); 651 break; 652 default: 653 if (substr($arg, 0, 7) === 'sniffs=') { 654 $sniffs = explode(',', substr($arg, 7)); 655 foreach ($sniffs as $sniff) { 656 if (substr_count($sniff, '.') !== 2) { 657 echo 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL; 658 $this->printUsage(); 659 exit(2); 660 } 661 } 662 663 $this->values['sniffs'] = $sniffs; 664 } else if (substr($arg, 0, 8) === 'exclude=') { 665 $sniffs = explode(',', substr($arg, 8)); 666 foreach ($sniffs as $sniff) { 667 if (substr_count($sniff, '.') !== 2) { 668 echo 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL; 669 $this->printUsage(); 670 exit(2); 671 } 672 } 673 674 $this->values['exclude'] = $sniffs; 675 } else if (substr($arg, 0, 10) === 'bootstrap=') { 676 $files = explode(',', substr($arg, 10)); 677 foreach ($files as $file) { 678 $path = PHP_CodeSniffer::realpath($file); 679 if ($path === false) { 680 echo 'ERROR: The specified bootstrap file "'.$file.'" does not exist'.PHP_EOL.PHP_EOL; 681 $this->printUsage(); 682 exit(2); 683 } 684 685 $this->values['bootstrap'][] = $path; 686 } 687 } else if (substr($arg, 0, 10) === 'file-list=') { 688 $fileList = substr($arg, 10); 689 $path = PHP_CodeSniffer::realpath($fileList); 690 if ($path === false) { 691 echo 'ERROR: The specified file list "'.$file.'" does not exist'.PHP_EOL.PHP_EOL; 692 $this->printUsage(); 693 exit(2); 694 } 695 696 $files = file($path); 697 foreach ($files as $inputFile) { 698 $inputFile = trim($inputFile); 699 700 // Skip empty lines. 701 if ($inputFile === '') { 702 continue; 703 } 704 705 $realFile = PHP_CodeSniffer::realpath($inputFile); 706 if ($realFile === false) { 707 echo 'ERROR: The specified file "'.$inputFile.'" does not exist'.PHP_EOL.PHP_EOL; 708 $this->printUsage(); 709 exit(2); 710 } 711 712 $this->values['files'][] = $realFile; 713 } 714 } else if (substr($arg, 0, 11) === 'stdin-path=') { 715 $this->values['stdinPath'] = PHP_CodeSniffer::realpath(substr($arg, 11)); 716 717 // It may not exist and return false instead, so just use whatever they gave us. 718 if ($this->values['stdinPath'] === false) { 719 $this->values['stdinPath'] = trim(substr($arg, 11)); 720 } 721 } else if (substr($arg, 0, 12) === 'report-file=') { 722 $this->values['reportFile'] = PHP_CodeSniffer::realpath(substr($arg, 12)); 723 724 // It may not exist and return false instead. 725 if ($this->values['reportFile'] === false) { 726 $this->values['reportFile'] = substr($arg, 12); 727 728 $dir = dirname($this->values['reportFile']); 729 if (is_dir($dir) === false) { 730 echo 'ERROR: The specified report file path "'.$this->values['reportFile'].'" points to a non-existent directory'.PHP_EOL.PHP_EOL; 731 $this->printUsage(); 732 exit(2); 733 } 734 735 if ($dir === '.') { 736 // Passed report file is a file in the current directory. 737 $this->values['reportFile'] = getcwd().'/'.basename($this->values['reportFile']); 738 } else { 739 if ($dir{0} === '/') { 740 // An absolute path. 741 $dir = PHP_CodeSniffer::realpath($dir); 742 } else { 743 $dir = PHP_CodeSniffer::realpath(getcwd().'/'.$dir); 744 } 745 746 if ($dir !== false) { 747 // Report file path is relative. 748 $this->values['reportFile'] = $dir.'/'.basename($this->values['reportFile']); 749 } 750 } 751 }//end if 752 753 if (is_dir($this->values['reportFile']) === true) { 754 echo 'ERROR: The specified report file path "'.$this->values['reportFile'].'" is a directory'.PHP_EOL.PHP_EOL; 755 $this->printUsage(); 756 exit(2); 757 } 758 } else if (substr($arg, 0, 13) === 'report-width=') { 759 $this->values['reportWidth'] = $this->_validateReportWidth(substr($arg, 13)); 760 } else if (substr($arg, 0, 7) === 'report=' 761 || substr($arg, 0, 7) === 'report-' 762 ) { 763 if ($arg[6] === '-') { 764 // This is a report with file output. 765 $split = strpos($arg, '='); 766 if ($split === false) { 767 $report = substr($arg, 7); 768 $output = null; 769 } else { 770 $report = substr($arg, 7, ($split - 7)); 771 $output = substr($arg, ($split + 1)); 772 if ($output === false) { 773 $output = null; 774 } else { 775 $dir = dirname($output); 776 if ($dir === '.') { 777 // Passed report file is a filename in the current directory. 778 $output = getcwd().'/'.basename($output); 779 } else { 780 if ($dir{0} === '/') { 781 // An absolute path. 782 $dir = PHP_CodeSniffer::realpath($dir); 783 } else { 784 $dir = PHP_CodeSniffer::realpath(getcwd().'/'.$dir); 785 } 786 787 if ($dir !== false) { 788 // Report file path is relative. 789 $output = $dir.'/'.basename($output); 790 } 791 } 792 }//end if 793 }//end if 794 } else { 795 // This is a single report. 796 $report = substr($arg, 7); 797 $output = null; 798 }//end if 799 800 $this->values['reports'][$report] = $output; 801 } else if (substr($arg, 0, 9) === 'standard=') { 802 $standards = trim(substr($arg, 9)); 803 if ($standards !== '') { 804 $this->values['standard'] = explode(',', $standards); 805 } 806 } else if (substr($arg, 0, 11) === 'extensions=') { 807 if (isset($this->values['extensions']) === false) { 808 $this->values['extensions'] = array(); 809 } 810 811 $this->values['extensions'] = array_merge($this->values['extensions'], explode(',', substr($arg, 11))); 812 } else if (substr($arg, 0, 9) === 'severity=') { 813 $this->values['errorSeverity'] = (int) substr($arg, 9); 814 $this->values['warningSeverity'] = $this->values['errorSeverity']; 815 } else if (substr($arg, 0, 15) === 'error-severity=') { 816 $this->values['errorSeverity'] = (int) substr($arg, 15); 817 } else if (substr($arg, 0, 17) === 'warning-severity=') { 818 $this->values['warningSeverity'] = (int) substr($arg, 17); 819 } else if (substr($arg, 0, 7) === 'ignore=') { 820 // Split the ignore string on commas, unless the comma is escaped 821 // using 1 or 3 slashes (\, or \\\,). 822 $ignored = preg_split( 823 '/(?<=(?<!\\\\)\\\\\\\\),|(?<!\\\\),/', 824 substr($arg, 7) 825 ); 826 foreach ($ignored as $pattern) { 827 $pattern = trim($pattern); 828 if ($pattern === '') { 829 continue; 830 } 831 832 $this->values['ignored'][$pattern] = 'absolute'; 833 } 834 } else if (substr($arg, 0, 10) === 'generator=') { 835 $this->values['generator'] = substr($arg, 10); 836 } else if (substr($arg, 0, 9) === 'encoding=') { 837 $this->values['encoding'] = strtolower(substr($arg, 9)); 838 } else if (substr($arg, 0, 10) === 'tab-width=') { 839 $this->values['tabWidth'] = (int) substr($arg, 10); 840 } else { 841 if ($this->dieOnUnknownArg === false) { 842 $eqPos = strpos($arg, '='); 843 if ($eqPos === false) { 844 $this->values[$arg] = $arg; 845 } else { 846 $value = substr($arg, ($eqPos + 1)); 847 $arg = substr($arg, 0, $eqPos); 848 $this->values[$arg] = $value; 849 } 850 } else { 851 $this->processUnknownArgument('--'.$arg, $pos); 852 } 853 }//end if 854 855 break; 856 }//end switch 857 858 }//end processLongArgument() 859 860 861 /** 862 * Processes an unknown command line argument. 863 * 864 * Assumes all unknown arguments are files and folders to check. 865 * 866 * @param string $arg The command line argument. 867 * @param int $pos The position of the argument on the command line. 868 * 869 * @return void 870 */ 871 public function processUnknownArgument($arg, $pos) 872 { 873 // We don't know about any additional switches; just files. 874 if ($arg{0} === '-') { 875 if ($this->dieOnUnknownArg === false) { 876 return; 877 } 878 879 echo 'ERROR: option "'.$arg.'" not known.'.PHP_EOL.PHP_EOL; 880 $this->printUsage(); 881 exit(2); 882 } 883 884 $file = PHP_CodeSniffer::realpath($arg); 885 if (file_exists($file) === false) { 886 if ($this->dieOnUnknownArg === false) { 887 return; 888 } 889 890 echo 'ERROR: The file "'.$arg.'" does not exist.'.PHP_EOL.PHP_EOL; 891 $this->printUsage(); 892 exit(2); 893 } else { 894 $this->values['files'][] = $file; 895 } 896 897 }//end processUnknownArgument() 898 899 900 /** 901 * Runs PHP_CodeSniffer over files and directories. 902 * 903 * @param array $values An array of values determined from CLI args. 904 * 905 * @return int The number of error and warning messages shown. 906 * @see getCommandLineValues() 907 */ 908 public function process($values=array()) 909 { 910 if (empty($values) === true) { 911 $values = $this->getCommandLineValues(); 912 } else { 913 $values = array_merge($this->getDefaults(), $values); 914 $this->values = $values; 915 } 916 917 if ($values['generator'] !== '') { 918 $phpcs = new PHP_CodeSniffer($values['verbosity']); 919 if ($values['standard'] === null) { 920 $values['standard'] = $this->validateStandard(null); 921 } 922 923 foreach ($values['standard'] as $standard) { 924 $phpcs->generateDocs( 925 $standard, 926 $values['sniffs'], 927 $values['generator'] 928 ); 929 } 930 931 exit(0); 932 } 933 934 // If no standard is supplied, get the default. 935 $values['standard'] = $this->validateStandard($values['standard']); 936 foreach ($values['standard'] as $standard) { 937 if (PHP_CodeSniffer::isInstalledStandard($standard) === false) { 938 // They didn't select a valid coding standard, so help them 939 // out by letting them know which standards are installed. 940 echo 'ERROR: the "'.$standard.'" coding standard is not installed. '; 941 $this->printInstalledStandards(); 942 exit(2); 943 } 944 } 945 946 if ($values['explain'] === true) { 947 foreach ($values['standard'] as $standard) { 948 $this->explainStandard($standard); 949 } 950 951 exit(0); 952 } 953 954 $phpcs = new PHP_CodeSniffer($values['verbosity'], null, null, null); 955 $phpcs->setCli($this); 956 $phpcs->initStandard($values['standard'], $values['sniffs'], $values['exclude']); 957 $values = $this->values; 958 959 $phpcs->setTabWidth($values['tabWidth']); 960 $phpcs->setEncoding($values['encoding']); 961 $phpcs->setInteractive($values['interactive']); 962 963 // Set file extensions if they were specified. Otherwise, 964 // let PHP_CodeSniffer decide on the defaults. 965 if (empty($values['extensions']) === false) { 966 $phpcs->setAllowedFileExtensions($values['extensions']); 967 } 968 969 // Set ignore patterns if they were specified. 970 if (empty($values['ignored']) === false) { 971 $ignorePatterns = array_merge($phpcs->getIgnorePatterns(), $values['ignored']); 972 $phpcs->setIgnorePatterns($ignorePatterns); 973 } 974 975 // Set some convenience member vars. 976 if ($values['errorSeverity'] === null) { 977 $this->errorSeverity = PHPCS_DEFAULT_ERROR_SEV; 978 } else { 979 $this->errorSeverity = $values['errorSeverity']; 980 } 981 982 if ($values['warningSeverity'] === null) { 983 $this->warningSeverity = PHPCS_DEFAULT_WARN_SEV; 984 } else { 985 $this->warningSeverity = $values['warningSeverity']; 986 } 987 988 if (empty($values['reports']) === true) { 989 $values['reports']['full'] = $values['reportFile']; 990 $this->values['reports'] = $values['reports']; 991 } 992 993 // Include bootstrap files. 994 foreach ($values['bootstrap'] as $bootstrap) { 995 include $bootstrap; 996 } 997 998 $phpcs->processFiles($values['files'], $values['local']); 999 1000 if (empty($values['files']) === true || $values['stdin'] !== null) { 1001 $fileContents = $values['stdin']; 1002 if ($fileContents === null) { 1003 // Check if they are passing in the file contents. 1004 $handle = fopen('php://stdin', 'r'); 1005 stream_set_blocking($handle, true); 1006 $fileContents = stream_get_contents($handle); 1007 fclose($handle); 1008 } 1009 1010 if ($fileContents === '') { 1011 // No files and no content passed in. 1012 echo 'ERROR: You must supply at least one file or directory to process.'.PHP_EOL.PHP_EOL; 1013 $this->printUsage(); 1014 exit(2); 1015 } else { 1016 $this->values['stdin'] = $fileContents; 1017 $phpcs->processFile('STDIN', $fileContents); 1018 } 1019 } 1020 1021 // Interactive runs don't require a final report and it doesn't really 1022 // matter what the retun value is because we know it isn't being read 1023 // by a script. 1024 if ($values['interactive'] === true) { 1025 return 0; 1026 } 1027 1028 return $this->printErrorReport( 1029 $phpcs, 1030 $values['reports'], 1031 $values['showSources'], 1032 $values['reportFile'], 1033 $values['reportWidth'] 1034 ); 1035 1036 }//end process() 1037 1038 1039 /** 1040 * Prints the error report for the run. 1041 * 1042 * Note that this function may actually print multiple reports 1043 * as the user may have specified a number of output formats. 1044 * 1045 * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object containing 1046 * the errors. 1047 * @param array $reports A list of reports to print. 1048 * @param bool $showSources TRUE if report should show error sources 1049 * (not used by all reports). 1050 * @param string $reportFile A default file to log report output to. 1051 * @param int $reportWidth How wide the screen reports should be. 1052 * 1053 * @return int The number of error and warning messages shown. 1054 */ 1055 public function printErrorReport( 1056 PHP_CodeSniffer $phpcs, 1057 $reports, 1058 $showSources, 1059 $reportFile, 1060 $reportWidth 1061 ) { 1062 if (empty($reports) === true) { 1063 $reports['full'] = $reportFile; 1064 } 1065 1066 $errors = 0; 1067 $warnings = 0; 1068 $toScreen = false; 1069 1070 foreach ($reports as $report => $output) { 1071 if ($output === null) { 1072 $output = $reportFile; 1073 } 1074 1075 if ($reportFile === null) { 1076 $toScreen = true; 1077 } 1078 1079 // We don't add errors here because the number of 1080 // errors reported by each report type will always be the 1081 // same, so we really just need 1 number. 1082 $result = $phpcs->reporting->printReport( 1083 $report, 1084 $showSources, 1085 $this->values, 1086 $output, 1087 $reportWidth 1088 ); 1089 1090 $errors = $result['errors']; 1091 $warnings = $result['warnings']; 1092 }//end foreach 1093 1094 // Only print timer output if no reports were 1095 // printed to the screen so we don't put additional output 1096 // in something like an XML report. If we are printing to screen, 1097 // the report types would have already worked out who should 1098 // print the timer info. 1099 if (PHP_CODESNIFFER_INTERACTIVE === false 1100 && ($toScreen === false 1101 || (($errors + $warnings) === 0 && $this->values['showProgress'] === true)) 1102 ) { 1103 PHP_CodeSniffer_Reporting::printRunTime(); 1104 } 1105 1106 // They should all return the same value, so it 1107 // doesn't matter which return value we end up using. 1108 $ignoreWarnings = PHP_CodeSniffer::getConfigData('ignore_warnings_on_exit'); 1109 $ignoreErrors = PHP_CodeSniffer::getConfigData('ignore_errors_on_exit'); 1110 1111 $return = ($errors + $warnings); 1112 if ($ignoreErrors !== null) { 1113 $ignoreErrors = (bool) $ignoreErrors; 1114 if ($ignoreErrors === true) { 1115 $return -= $errors; 1116 } 1117 } 1118 1119 if ($ignoreWarnings !== null) { 1120 $ignoreWarnings = (bool) $ignoreWarnings; 1121 if ($ignoreWarnings === true) { 1122 $return -= $warnings; 1123 } 1124 } 1125 1126 return $return; 1127 1128 }//end printErrorReport() 1129 1130 1131 /** 1132 * Convert the passed standards into valid standards. 1133 * 1134 * Checks things like default values and case. 1135 * 1136 * @param array $standards The standards to validate. 1137 * 1138 * @return array 1139 */ 1140 public function validateStandard($standards) 1141 { 1142 if ($standards === null) { 1143 // They did not supply a standard to use. 1144 // Look for a default ruleset in the current directory or higher. 1145 $currentDir = getcwd(); 1146 1147 do { 1148 $default = $currentDir.DIRECTORY_SEPARATOR.'phpcs.xml'; 1149 if (is_file($default) === true) { 1150 return array($default); 1151 } 1152 1153 $default = $currentDir.DIRECTORY_SEPARATOR.'phpcs.xml.dist'; 1154 if (is_file($default) === true) { 1155 return array($default); 1156 } 1157 1158 $lastDir = $currentDir; 1159 $currentDir = dirname($currentDir); 1160 } while ($currentDir !== '.' && $currentDir !== $lastDir); 1161 1162 // Try to get the default from the config system. 1163 $standard = PHP_CodeSniffer::getConfigData('default_standard'); 1164 if ($standard === null) { 1165 // Product default standard. 1166 $standard = 'PEAR'; 1167 } 1168 1169 return explode(',', $standard); 1170 }//end if 1171 1172 $cleaned = array(); 1173 $standards = (array) $standards; 1174 1175 // Check if the standard name is valid, or if the case is invalid. 1176 $installedStandards = PHP_CodeSniffer::getInstalledStandards(); 1177 foreach ($standards as $standard) { 1178 foreach ($installedStandards as $validStandard) { 1179 if (strtolower($standard) === strtolower($validStandard)) { 1180 $standard = $validStandard; 1181 break; 1182 } 1183 } 1184 1185 $cleaned[] = $standard; 1186 } 1187 1188 return $cleaned; 1189 1190 }//end validateStandard() 1191 1192 1193 /** 1194 * Prints a report showing the sniffs contained in a standard. 1195 * 1196 * @param string $standard The standard to validate. 1197 * 1198 * @return void 1199 */ 1200 public function explainStandard($standard) 1201 { 1202 $phpcs = new PHP_CodeSniffer(); 1203 $phpcs->process(array(), $standard); 1204 $sniffs = $phpcs->getSniffs(); 1205 $sniffs = array_keys($sniffs); 1206 sort($sniffs); 1207 1208 ob_start(); 1209 1210 $lastStandard = ''; 1211 $lastCount = ''; 1212 $sniffCount = count($sniffs); 1213 $sniffs[] = '___'; 1214 1215 echo PHP_EOL."The $standard standard contains $sniffCount sniffs".PHP_EOL; 1216 1217 ob_start(); 1218 1219 foreach ($sniffs as $sniff) { 1220 $parts = explode('_', str_replace('\\', '_', $sniff)); 1221 if ($lastStandard === '') { 1222 $lastStandard = $parts[0]; 1223 } 1224 1225 if ($parts[0] !== $lastStandard) { 1226 $sniffList = ob_get_contents(); 1227 ob_end_clean(); 1228 1229 echo PHP_EOL.$lastStandard.' ('.$lastCount.' sniffs)'.PHP_EOL; 1230 echo str_repeat('-', (strlen($lastStandard.$lastCount) + 10)); 1231 echo PHP_EOL; 1232 echo $sniffList; 1233 1234 $lastStandard = $parts[0]; 1235 $lastCount = 0; 1236 1237 ob_start(); 1238 } 1239 1240 echo ' '.$parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5).PHP_EOL; 1241 $lastCount++; 1242 }//end foreach 1243 1244 ob_end_clean(); 1245 1246 }//end explainStandard() 1247 1248 1249 /** 1250 * Prints out the gathered config data. 1251 * 1252 * @param array $data The config data to print. 1253 * 1254 * @return void 1255 */ 1256 public function printConfigData($data) 1257 { 1258 $max = 0; 1259 $keys = array_keys($data); 1260 foreach ($keys as $key) { 1261 $len = strlen($key); 1262 if (strlen($key) > $max) { 1263 $max = $len; 1264 } 1265 } 1266 1267 if ($max === 0) { 1268 return; 1269 } 1270 1271 $max += 2; 1272 ksort($data); 1273 foreach ($data as $name => $value) { 1274 echo str_pad($name.': ', $max).$value.PHP_EOL; 1275 } 1276 1277 }//end printConfigData() 1278 1279 1280 /** 1281 * Prints out the usage information for this script. 1282 * 1283 * @return void 1284 */ 1285 public function printUsage() 1286 { 1287 if (PHP_CODESNIFFER_CBF === true) { 1288 $this->printPHPCBFUsage(); 1289 } else { 1290 $this->printPHPCSUsage(); 1291 } 1292 1293 }//end printUsage() 1294 1295 1296 /** 1297 * Prints out the usage information for PHPCS. 1298 * 1299 * @return void 1300 */ 1301 public function printPHPCSUsage() 1302 { 1303 echo 'Usage: phpcs [-nwlsaepqvi] [-d key[=value]] [--colors] [--no-colors] [--stdin-path=<stdinPath>]'.PHP_EOL; 1304 echo ' [--report=<report>] [--report-file=<reportFile>] [--report-<report>=<reportFile>] ...'.PHP_EOL; 1305 echo ' [--report-width=<reportWidth>] [--generator=<generator>] [--tab-width=<tabWidth>]'.PHP_EOL; 1306 echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL; 1307 echo ' [--runtime-set key value] [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL; 1308 echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>] [--encoding=<encoding>]'.PHP_EOL; 1309 echo ' [--extensions=<extensions>] [--ignore=<patterns>] [--bootstrap=<bootstrap>]'.PHP_EOL; 1310 echo ' [--file-list=<fileList>] <file> ...'.PHP_EOL; 1311 echo ' Set runtime value (see --config-set) '.PHP_EOL; 1312 echo ' -n Do not print warnings (shortcut for --warning-severity=0)'.PHP_EOL; 1313 echo ' -w Print both warnings and errors (this is the default)'.PHP_EOL; 1314 echo ' -l Local directory only, no recursion'.PHP_EOL; 1315 echo ' -s Show sniff codes in all reports'.PHP_EOL; 1316 echo ' -a Run interactively'.PHP_EOL; 1317 echo ' -e Explain a standard by showing the sniffs it includes'.PHP_EOL; 1318 echo ' -p Show progress of the run'.PHP_EOL; 1319 echo ' -q Quiet mode; disables progress and verbose output'.PHP_EOL; 1320 echo ' -v[v][v] Print verbose output'.PHP_EOL; 1321 echo ' -i Show a list of installed coding standards'.PHP_EOL; 1322 echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL; 1323 echo ' --help Print this help message'.PHP_EOL; 1324 echo ' --version Print version information'.PHP_EOL; 1325 echo ' --colors Use colors in output'.PHP_EOL; 1326 echo ' --no-colors Do not use colors in output (this is the default)'.PHP_EOL; 1327 echo ' <file> One or more files and/or directories to check'.PHP_EOL; 1328 echo ' <fileList> A file containing a list of files and/or directories to check (one per line)'.PHP_EOL; 1329 echo ' <stdinPath> If processing STDIN, the file path that STDIN will be processed as '.PHP_EOL; 1330 echo ' <bootstrap> A comma separated list of files to run before processing starts'.PHP_EOL; 1331 echo ' <encoding> The encoding of the files being checked (default is iso-8859-1)'.PHP_EOL; 1332 echo ' <extensions> A comma separated list of file extensions to check'.PHP_EOL; 1333 echo ' (extension filtering only valid when checking a directory)'.PHP_EOL; 1334 echo ' The type of the file can be specified using: ext/type'.PHP_EOL; 1335 echo ' e.g., module/php,es/js'.PHP_EOL; 1336 echo ' <generator> Uses either the "HTML", "Markdown" or "Text" generator'.PHP_EOL; 1337 echo ' (forces documentation generation instead of checking)'.PHP_EOL; 1338 echo ' <patterns> A comma separated list of patterns to ignore files and directories'.PHP_EOL; 1339 echo ' <report> Print either the "full", "xml", "checkstyle", "csv"'.PHP_EOL; 1340 echo ' "json", "emacs", "source", "summary", "diff", "junit"'.PHP_EOL; 1341 echo ' "svnblame", "gitblame", "hgblame" or "notifysend" report'.PHP_EOL; 1342 echo ' (the "full" report is printed by default)'.PHP_EOL; 1343 echo ' <reportFile> Write the report to the specified file path'.PHP_EOL; 1344 echo ' <reportWidth> How many columns wide screen reports should be printed'.PHP_EOL; 1345 echo ' or set to "auto" to use current screen width, where supported'.PHP_EOL; 1346 echo ' <sniffs> A comma separated list of sniff codes to include or exclude during checking'.PHP_EOL; 1347 echo ' (all sniffs must be part of the specified standard)'.PHP_EOL; 1348 echo ' <severity> The minimum severity required to display an error or warning'.PHP_EOL; 1349 echo ' <standard> The name or path of the coding standard to use'.PHP_EOL; 1350 echo ' <tabWidth> The number of spaces each tab represents'.PHP_EOL; 1351 1352 }//end printPHPCSUsage() 1353 1354 1355 /** 1356 * Prints out the usage information for PHPCBF. 1357 * 1358 * @return void 1359 */ 1360 public function printPHPCBFUsage() 1361 { 1362 echo 'Usage: phpcbf [-nwli] [-d key[=value]] [--stdin-path=<stdinPath>]'.PHP_EOL; 1363 echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>] [--suffix=<suffix>]'.PHP_EOL; 1364 echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL; 1365 echo ' [--tab-width=<tabWidth>] [--encoding=<encoding>]'.PHP_EOL; 1366 echo ' [--extensions=<extensions>] [--ignore=<patterns>] [--bootstrap=<bootstrap>]'.PHP_EOL; 1367 echo ' [--file-list=<fileList>] <file> ...'.PHP_EOL; 1368 echo ' -n Do not fix warnings (shortcut for --warning-severity=0)'.PHP_EOL; 1369 echo ' -w Fix both warnings and errors (on by default)'.PHP_EOL; 1370 echo ' -l Local directory only, no recursion'.PHP_EOL; 1371 echo ' -i Show a list of installed coding standards'.PHP_EOL; 1372 echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL; 1373 echo ' --help Print this help message'.PHP_EOL; 1374 echo ' --version Print version information'.PHP_EOL; 1375 echo ' --no-patch Do not make use of the "diff" or "patch" programs'.PHP_EOL; 1376 echo ' <file> One or more files and/or directories to fix'.PHP_EOL; 1377 echo ' <fileList> A file containing a list of files and/or directories to fix (one per line)'.PHP_EOL; 1378 echo ' <stdinPath> If processing STDIN, the file path that STDIN will be processed as '.PHP_EOL; 1379 echo ' <bootstrap> A comma separated list of files to run before processing starts'.PHP_EOL; 1380 echo ' <encoding> The encoding of the files being fixed (default is iso-8859-1)'.PHP_EOL; 1381 echo ' <extensions> A comma separated list of file extensions to fix'.PHP_EOL; 1382 echo ' (extension filtering only valid when checking a directory)'.PHP_EOL; 1383 echo ' The type of the file can be specified using: ext/type'.PHP_EOL; 1384 echo ' e.g., module/php,es/js'.PHP_EOL; 1385 echo ' <patterns> A comma separated list of patterns to ignore files and directories'.PHP_EOL; 1386 echo ' <sniffs> A comma separated list of sniff codes to include or exclude during fixing'.PHP_EOL; 1387 echo ' (all sniffs must be part of the specified standard)'.PHP_EOL; 1388 echo ' <severity> The minimum severity required to fix an error or warning'.PHP_EOL; 1389 echo ' <standard> The name or path of the coding standard to use'.PHP_EOL; 1390 echo ' <suffix> Write modified files to a filename using this suffix'.PHP_EOL; 1391 echo ' ("diff" and "patch" are not used in this mode)'.PHP_EOL; 1392 echo ' <tabWidth> The number of spaces each tab represents'.PHP_EOL; 1393 1394 }//end printPHPCBFUsage() 1395 1396 1397 /** 1398 * Prints out a list of installed coding standards. 1399 * 1400 * @return void 1401 */ 1402 public function printInstalledStandards() 1403 { 1404 $installedStandards = PHP_CodeSniffer::getInstalledStandards(); 1405 $numStandards = count($installedStandards); 1406 1407 if ($numStandards === 0) { 1408 echo 'No coding standards are installed.'.PHP_EOL; 1409 } else { 1410 $lastStandard = array_pop($installedStandards); 1411 if ($numStandards === 1) { 1412 echo "The only coding standard installed is $lastStandard".PHP_EOL; 1413 } else { 1414 $standardList = implode(', ', $installedStandards); 1415 $standardList .= ' and '.$lastStandard; 1416 echo 'The installed coding standards are '.$standardList.PHP_EOL; 1417 } 1418 } 1419 1420 }//end printInstalledStandards() 1421 1422 1423 /** 1424 * Set report width based on terminal width. 1425 * 1426 * @param int $width The width of the report. If "auto" then will 1427 * be replaced by the terminal width. 1428 * 1429 * @return int 1430 */ 1431 private function _validateReportWidth($width) 1432 { 1433 if ($width === 'auto' 1434 && preg_match('|\d+ (\d+)|', shell_exec('stty size 2>&1'), $matches) === 1 1435 ) { 1436 return (int) $matches[1]; 1437 } 1438 1439 return (int) $width; 1440 1441 }//end _validateReportWidth() 1442 1443 1444}//end class 1445