PHP_CodeSniffer
[ class tree: PHP_CodeSniffer ] [ index: PHP_CodeSniffer ] [ all elements ]

Source for file Config.php

Documentation is available at Config.php

  1. <?php
  2. /**
  3.  * Stores the configuration used to run PHPCS and PHPCBF.
  4.  *
  5.  * Parses the command line to determine user supplied values
  6.  * and provides functions to access data stored in config files.
  7.  *
  8.  * @author    Greg Sherwood <gsherwood@squiz.net>
  9.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  10.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  11.  */
  12.  
  13. namespace PHP_CodeSniffer;
  14.  
  15. use PHP_CodeSniffer\Exceptions\RuntimeException;
  16. use PHP_CodeSniffer\Exceptions\DeepExitException;
  17.  
  18. class Config
  19. {
  20.  
  21.     /**
  22.      * The current version.
  23.      *
  24.      * @var string 
  25.      */
  26.     const VERSION = '3.1.1';
  27.  
  28.     /**
  29.      * Package stability; either stable, beta or alpha.
  30.      *
  31.      * @var string 
  32.      */
  33.     const STABILITY = 'stable';
  34.  
  35.     /**
  36.      * An array of settings that PHPCS and PHPCBF accept.
  37.      *
  38.      * This array is not meant to be accessed directly. Instead, use the settings
  39.      * as if they are class member vars so the __get() and __set() magic methods
  40.      * can be used to validate the values. For example, to set the verbosity level to
  41.      * level 2, use $this->verbosity = 2; instead of accessing this property directly.
  42.      *
  43.      * The list of settings are:
  44.      *
  45.      * string[] files           The files and directories to check.
  46.      * string[] standards       The standards being used for checking.
  47.      * int      verbosity       How verbose the output should be.
  48.      *                          0: no unnecessary output
  49.      *                          1: basic output for files being checked
  50.      *                          2: ruleset and file parsing output
  51.      *                          3: sniff execution output
  52.      * bool     interactive     Enable interactive checking mode.
  53.      * bool     parallel        Check files in parallel.
  54.      * bool     cache           Enable the use of the file cache.
  55.      * bool     cacheFile       A file where the cache data should be written
  56.      * bool     colors          Display colours in output.
  57.      * bool     explain         Explain the coding standards.
  58.      * bool     local           Process local files in directories only (no recursion).
  59.      * bool     showSources     Show sniff source codes in report output.
  60.      * bool     showProgress    Show basic progress information while running.
  61.      * bool     quiet           Quiet mode; disables progress and verbose output.
  62.      * bool     annotations     Process @codingStandard annotations.
  63.      * int      tabWidth        How many spaces each tab is worth.
  64.      * string   encoding        The encoding of the files being checked.
  65.      * string[] sniffs          The sniffs that should be used for checking.
  66.      *                          If empty, all sniffs in the supplied standards will be used.
  67.      * string[] exclude         The sniffs that should be excluded from checking.
  68.      *                          If empty, all sniffs in the supplied standards will be used.
  69.      * string[] ignored         Regular expressions used to ignore files and folders during checking.
  70.      * string   reportFile      A file where the report output should be written.
  71.      * string   generator       The documentation generator to use.
  72.      * string   filter          The filter to use for the run.
  73.      * string[] bootstrap       One of more files to include before the run begins.
  74.      * int      reportWidth     The maximum number of columns that reports should use for output.
  75.      *                          Set to "auto" for have this value changed to the width of the terminal.
  76.      * int      errorSeverity   The minimum severity an error must have to be displayed.
  77.      * int      warningSeverity The minimum severity a warning must have to be displayed.
  78.      * bool     recordErrors    Record the content of error messages as well as error counts.
  79.      * string   suffix          A suffix to add to fixed files.
  80.      * string   basepath        A file system location to strip from the paths of files shown in reports.
  81.      * bool     stdin           Read content from STDIN instead of supplied files.
  82.      * string   stdinContent    Content passed directly to PHPCS on STDIN.
  83.      * string   stdinPath       The path to use for content passed on STDIN.
  84.      *
  85.      * array<string, string>      extensions File extensions that should be checked, and what tokenizer to use.
  86.      *                                       E.g., array('inc' => 'PHP');
  87.      * array<string, string|null> reports    The reports to use for printing output after the run.
  88.      *                                       The format of the array is:
  89.      *                                           array(
  90.      *                                            'reportName1' => 'outputFile',
  91.      *                                            'reportName2' => null,
  92.      *                                           );
  93.      *                                       If the array value is NULL, the report will be written to the screen.
  94.      *
  95.      * string[] unknown Any arguments gathered on the command line that are unknown to us.
  96.      *                  E.g., using `phpcs -c` will give array('c');
  97.      *
  98.      * @var array<string, mixed>
  99.      */
  100.     private $settings = array(
  101.                          'files'           => null,
  102.                          'standards'       => null,
  103.                          'verbosity'       => null,
  104.                          'interactive'     => null,
  105.                          'parallel'        => null,
  106.                          'cache'           => null,
  107.                          'cacheFile'       => null,
  108.                          'colors'          => null,
  109.                          'explain'         => null,
  110.                          'local'           => null,
  111.                          'showSources'     => null,
  112.                          'showProgress'    => null,
  113.                          'quiet'           => null,
  114.                          'annotations'     => null,
  115.                          'tabWidth'        => null,
  116.                          'encoding'        => null,
  117.                          'extensions'      => null,
  118.                          'sniffs'          => null,
  119.                          'exclude'         => null,
  120.                          'ignored'         => null,
  121.                          'reportFile'      => null,
  122.                          'generator'       => null,
  123.                          'filter'          => null,
  124.                          'bootstrap'       => null,
  125.                          'reports'         => null,
  126.                          'basepath'        => null,
  127.                          'reportWidth'     => null,
  128.                          'errorSeverity'   => null,
  129.                          'warningSeverity' => null,
  130.                          'recordErrors'    => null,
  131.                          'suffix'          => null,
  132.                          'stdin'           => null,
  133.                          'stdinContent'    => null,
  134.                          'stdinPath'       => null,
  135.                          'unknown'         => null,
  136.                         );
  137.  
  138.     /**
  139.      * Whether or not to kill the process when an unknown command line arg is found.
  140.      *
  141.      * If FALSE, arguments that are not command line options or file/directory paths
  142.      * will be ignored and execution will continue. These values will be stored in
  143.      * $this->unknown.
  144.      *
  145.      * @var boolean 
  146.      */
  147.     public $dieOnUnknownArg;
  148.  
  149.     /**
  150.      * The current command line arguments we are processing.
  151.      *
  152.      * @var string[] 
  153.      */
  154.     private $cliArgs = array();
  155.  
  156.     /**
  157.      * Command line values that the user has supplied directly.
  158.      *
  159.      * @var array<string, TRUE>
  160.      */
  161.     private $overriddenDefaults = array();
  162.  
  163.     /**
  164.      * Config file data that has been loaded for the run.
  165.      *
  166.      * @var array<string, string>
  167.      */
  168.     private static $configData = null;
  169.  
  170.     /**
  171.      * The full path to the config data file that has been loaded.
  172.      *
  173.      * @var string 
  174.      */
  175.     private static $configDataFile = null;
  176.  
  177.     /**
  178.      * Automatically discovered executable utility paths.
  179.      *
  180.      * @var array<string, string>
  181.      */
  182.     private static $executablePaths = array();
  183.  
  184.  
  185.     /**
  186.      * Get the value of an inaccessible property.
  187.      *
  188.      * @param string $name The name of the property.
  189.      *
  190.      * @return mixed 
  191.      * @throws RuntimeException If the setting name is invalid.
  192.      */
  193.     public function __get($name)
  194.     {
  195.         if (array_key_exists($name, $this->settings) === false) {
  196.             throw new RuntimeException("ERROR: unable to get value of property \"$name\"");
  197.         }
  198.  
  199.         return $this->settings[$name];
  200.  
  201.     }//end __get()
  202.  
  203.  
  204.     /**
  205.      * Set the value of an inaccessible property.
  206.      *
  207.      * @param string $name  The name of the property.
  208.      * @param mixed  $value The value of the property.
  209.      *
  210.      * @return void 
  211.      * @throws RuntimeException If the setting name is invalid.
  212.      */
  213.     public function __set($name, $value)
  214.     {
  215.         if (array_key_exists($name, $this->settings) === false) {
  216.             throw new RuntimeException("Can't __set() $name; setting doesn't exist");
  217.         }
  218.  
  219.         switch ($name) {
  220.         case 'reportWidth' :
  221.             // Support auto terminal width.
  222.             if ($value === 'auto' && preg_match('|\d+ (\d+)|', shell_exec('stty size 2>&1'), $matches) === 1) {
  223.                 $value = (int) $matches[1];
  224.             } else {
  225.                 $value = (int) $value;
  226.             }
  227.             break;
  228.         case 'standards' :
  229.             $cleaned = array();
  230.  
  231.             // Check if the standard name is valid, or if the case is invalid.
  232.             $installedStandards = Util\Standards::getInstalledStandards();
  233.             foreach ($value as $standard) {
  234.                 foreach ($installedStandards as $validStandard) {
  235.                     if (strtolower($standard) === strtolower($validStandard)) {
  236.                         $standard = $validStandard;
  237.                         break;
  238.                     }
  239.                 }
  240.  
  241.                 $cleaned[] = $standard;
  242.             }
  243.  
  244.             $value = $cleaned;
  245.             break;
  246.         default :
  247.             // No validation required.
  248.             break;
  249.         }//end switch
  250.  
  251.         $this->settings[$name] = $value;
  252.  
  253.     }//end __set()
  254.  
  255.  
  256.     /**
  257.      * Check if the value of an inaccessible property is set.
  258.      *
  259.      * @param string $name The name of the property.
  260.      *
  261.      * @return bool 
  262.      */
  263.     public function __isset($name)
  264.     {
  265.         return isset($this->settings[$name]);
  266.  
  267.     }//end __isset()
  268.  
  269.  
  270.     /**
  271.      * Unset the value of an inaccessible property.
  272.      *
  273.      * @param string $name The name of the property.
  274.      *
  275.      * @return void 
  276.      */
  277.     public function __unset($name)
  278.     {
  279.         $this->settings[$name] = null;
  280.  
  281.     }//end __unset()
  282.  
  283.  
  284.     /**
  285.      * Get the array of all config settings.
  286.      *
  287.      * @return array<string, mixed>
  288.      */
  289.     public function getSettings()
  290.     {
  291.         return $this->settings;
  292.  
  293.     }//end getSettings()
  294.  
  295.  
  296.     /**
  297.      * Set the array of all config settings.
  298.      *
  299.      * @param array<string, mixed> $settings The array of config settings.
  300.      *
  301.      * @return void 
  302.      */
  303.     public function setSettings($settings)
  304.     {
  305.         return $this->settings = $settings;
  306.  
  307.     }//end setSettings()
  308.  
  309.  
  310.     /**
  311.      * Creates a Config object and populates it with command line values.
  312.      *
  313.      * @param array $cliArgs         An array of values gathered from CLI args.
  314.      * @param bool  $dieOnUnknownArg Whether or not to kill the process when an
  315.      *                                unknown command line arg is found.
  316.      *
  317.      * @return void 
  318.      */
  319.     public function __construct(array $cliArgs=array(), $dieOnUnknownArg=true)
  320.     {
  321.         if (defined('PHP_CODESNIFFER_IN_TESTS') === true) {
  322.             // Let everything through during testing so that we can
  323.             // make use of PHPUnit command line arguments as well.
  324.             $this->dieOnUnknownArg = false;
  325.         } else {
  326.             $this->dieOnUnknownArg = $dieOnUnknownArg;
  327.         }
  328.  
  329.         $checkStdin = false;
  330.         if (empty($cliArgs) === true) {
  331.             $cliArgs = $_SERVER['argv'];
  332.             array_shift($cliArgs);
  333.             $checkStdin = true;
  334.         }
  335.  
  336.         $this->restoreDefaults();
  337.         $this->setCommandLineValues($cliArgs);
  338.  
  339.         if (isset($this->overriddenDefaults['standards']) === false) {
  340.             // They did not supply a standard to use.
  341.             // Look for a default ruleset in the current directory or higher.
  342.             $currentDir = getcwd();
  343.  
  344.             $defaultFiles = array(
  345.                              '.phpcs.xml',
  346.                              'phpcs.xml',
  347.                              '.phpcs.xml.dist',
  348.                              'phpcs.xml.dist',
  349.                             );
  350.  
  351.             do {
  352.                 foreach ($defaultFiles as $defaultFilename) {
  353.                     $default = $currentDir.DIRECTORY_SEPARATOR.$defaultFilename;
  354.                     if (is_file($default) === true) {
  355.                         $this->standards = array($default);
  356.                         break(2);
  357.                     }
  358.                 }
  359.  
  360.                 $lastDir    = $currentDir;
  361.                 $currentDir = dirname($currentDir);
  362.             } while ($currentDir !== '.' && $currentDir !== $lastDir);
  363.         }//end if
  364.  
  365.         // Check for content on STDIN.
  366.         if ($checkStdin === true) {
  367.             $handle = fopen('php://stdin', 'r');
  368.             if (stream_set_blocking($handle, false) === true) {
  369.                 $fileContents = '';
  370.                 while (($line = fgets($handle)) !== false) {
  371.                     $fileContents .= $line;
  372.                     usleep(10);
  373.                 }
  374.  
  375.                 stream_set_blocking($handle, true);
  376.                 fclose($handle);
  377.                 if (trim($fileContents) !== '') {
  378.                     $this->stdin        = true;
  379.                     $this->stdinContent = $fileContents;
  380.                     $this->overriddenDefaults['stdin']        = true;
  381.                     $this->overriddenDefaults['stdinContent'] = true;
  382.                 }
  383.             }
  384.         }
  385.  
  386.     }//end __construct()
  387.  
  388.  
  389.     /**
  390.      * Set the command line values.
  391.      *
  392.      * @param array $args An array of command line arguments to set.
  393.      *
  394.      * @return void 
  395.      */
  396.     public function setCommandLineValues($args)
  397.     {
  398.         $this->cliArgs = $args;
  399.         $numArgs       = count($args);
  400.  
  401.         for ($i = 0; $i < $numArgs; $i++) {
  402.             $arg = $this->cliArgs[$i];
  403.             if ($arg === '') {
  404.                 continue;
  405.             }
  406.  
  407.             if ($arg{0} === '-') {
  408.                 if ($arg === '-') {
  409.                     // Asking to read from STDIN.
  410.                     $this->stdin = true;
  411.                     $this->overriddenDefaults['stdin'] = true;
  412.                     continue;
  413.                 }
  414.  
  415.                 if ($arg === '--') {
  416.                     // Empty argument, ignore it.
  417.                     continue;
  418.                 }
  419.  
  420.                 if ($arg{1} === '-') {
  421.                     $this->processLongArgument(substr($arg, 2), $i);
  422.                 } else {
  423.                     $switches = str_split($arg);
  424.                     foreach ($switches as $switch) {
  425.                         if ($switch === '-') {
  426.                             continue;
  427.                         }
  428.  
  429.                         $this->processShortArgument($switch, $i);
  430.                     }
  431.                 }
  432.             } else {
  433.                 $this->processUnknownArgument($arg, $i);
  434.             }//end if
  435.         }//end for
  436.  
  437.     }//end setCommandLineValues()
  438.  
  439.  
  440.     /**
  441.      * Restore default values for all possible command line arguments.
  442.      *
  443.      * @return array 
  444.      */
  445.     public function restoreDefaults()
  446.     {
  447.         $this->files           = array();
  448.         $this->standards       = array('PEAR');
  449.         $this->verbosity       = 0;
  450.         $this->interactive     = false;
  451.         $this->cache           = false;
  452.         $this->cacheFile       = null;
  453.         $this->colors          = false;
  454.         $this->explain         = false;
  455.         $this->local           = false;
  456.         $this->showSources     = false;
  457.         $this->showProgress    = false;
  458.         $this->quiet           = false;
  459.         $this->annotations     = true;
  460.         $this->parallel        = 1;
  461.         $this->tabWidth        = 0;
  462.         $this->encoding        = 'utf-8';
  463.         $this->extensions      = array(
  464.                                   'php' => 'PHP',
  465.                                   'inc' => 'PHP',
  466.                                   'js'  => 'JS',
  467.                                   'css' => 'CSS',
  468.                                  );
  469.         $this->sniffs          = array();
  470.         $this->exclude         = array();
  471.         $this->ignored         = array();
  472.         $this->reportFile      = null;
  473.         $this->generator       = null;
  474.         $this->filter          = null;
  475.         $this->bootstrap       = array();
  476.         $this->basepath        = null;
  477.         $this->reports         = array('full' => null);
  478.         $this->reportWidth     = 'auto';
  479.         $this->errorSeverity   = 5;
  480.         $this->warningSeverity = 5;
  481.         $this->recordErrors    = true;
  482.         $this->suffix          = '';
  483.         $this->stdin           = false;
  484.         $this->stdinContent    = null;
  485.         $this->stdinPath       = null;
  486.         $this->unknown         = array();
  487.  
  488.         $standard = self::getConfigData('default_standard');
  489.         if ($standard !== null) {
  490.             $this->standards = explode(',', $standard);
  491.         }
  492.  
  493.         $reportFormat = self::getConfigData('report_format');
  494.         if ($reportFormat !== null) {
  495.             $this->reports = array($reportFormat => null);
  496.         }
  497.  
  498.         $tabWidth = self::getConfigData('tab_width');
  499.         if ($tabWidth !== null) {
  500.             $this->tabWidth = (int) $tabWidth;
  501.         }
  502.  
  503.         $encoding = self::getConfigData('encoding');
  504.         if ($encoding !== null) {
  505.             $this->encoding = strtolower($encoding);
  506.         }
  507.  
  508.         $severity = self::getConfigData('severity');
  509.         if ($severity !== null) {
  510.             $this->errorSeverity   = (int) $severity;
  511.             $this->warningSeverity = (int) $severity;
  512.         }
  513.  
  514.         $severity = self::getConfigData('error_severity');
  515.         if ($severity !== null) {
  516.             $this->errorSeverity = (int) $severity;
  517.         }
  518.  
  519.         $severity = self::getConfigData('warning_severity');
  520.         if ($severity !== null) {
  521.             $this->warningSeverity = (int) $severity;
  522.         }
  523.  
  524.         $showWarnings = self::getConfigData('show_warnings');
  525.         if ($showWarnings !== null) {
  526.             $showWarnings = (bool) $showWarnings;
  527.             if ($showWarnings === false) {
  528.                 $this->warningSeverity = 0;
  529.             }
  530.         }
  531.  
  532.         $reportWidth = self::getConfigData('report_width');
  533.         if ($reportWidth !== null) {
  534.             $this->reportWidth = $reportWidth;
  535.         }
  536.  
  537.         $showProgress = self::getConfigData('show_progress');
  538.         if ($showProgress !== null) {
  539.             $this->showProgress = (bool) $showProgress;
  540.         }
  541.  
  542.         $quiet = self::getConfigData('quiet');
  543.         if ($quiet !== null) {
  544.             $this->quiet = (bool) $quiet;
  545.         }
  546.  
  547.         $colors = self::getConfigData('colors');
  548.         if ($colors !== null) {
  549.             $this->colors = (bool) $colors;
  550.         }
  551.  
  552.         if (defined('PHP_CODESNIFFER_IN_TESTS') === false) {
  553.             $cache = self::getConfigData('cache');
  554.             if ($cache !== null) {
  555.                 $this->cache = (bool) $cache;
  556.             }
  557.  
  558.             $parallel = self::getConfigData('parallel');
  559.             if ($parallel !== null) {
  560.                 $this->parallel = max((int) $parallel, 1);
  561.             }
  562.         }
  563.  
  564.     }//end restoreDefaults()
  565.  
  566.  
  567.     /**
  568.      * Processes a short (-e) command line argument.
  569.      *
  570.      * @param string $arg The command line argument.
  571.      * @param int    $pos The position of the argument on the command line.
  572.      *
  573.      * @return void 
  574.      */
  575.     public function processShortArgument($arg, $pos)
  576.     {
  577.         switch ($arg) {
  578.         case 'h':
  579.         case '?':
  580.             ob_start();
  581.             $this->printUsage();
  582.             $output = ob_get_contents();
  583.             ob_end_clean();
  584.             throw new DeepExitException($output, 0);
  585.         case 'i' :
  586.             ob_start();
  587.             Util\Standards::printInstalledStandards();
  588.             $output = ob_get_contents();
  589.             ob_end_clean();
  590.             throw new DeepExitException($output, 0);
  591.         case 'v' :
  592.             if ($this->quiet === true) {
  593.                 // Ignore when quiet mode is enabled.
  594.                 break;
  595.             }
  596.  
  597.             $this->verbosity++;
  598.             $this->overriddenDefaults['verbosity'] = true;
  599.             break;
  600.         case 'l' :
  601.             $this->local = true;
  602.             $this->overriddenDefaults['local'] = true;
  603.             break;
  604.         case 's' :
  605.             $this->showSources = true;
  606.             $this->overriddenDefaults['showSources'] = true;
  607.             break;
  608.         case 'a' :
  609.             $this->interactive = true;
  610.             $this->overriddenDefaults['interactive'] = true;
  611.             break;
  612.         case 'e':
  613.             $this->explain = true;
  614.             $this->overriddenDefaults['explain'] = true;
  615.             break;
  616.         case 'p' :
  617.             if ($this->quiet === true) {
  618.                 // Ignore when quiet mode is enabled.
  619.                 break;
  620.             }
  621.  
  622.             $this->showProgress = true;
  623.             $this->overriddenDefaults['showProgress'] = true;
  624.             break;
  625.         case 'q' :
  626.             // Quiet mode disables a few other settings as well.
  627.             $this->quiet        = true;
  628.             $this->showProgress = false;
  629.             $this->verbosity    = 0;
  630.  
  631.             $this->overriddenDefaults['quiet'] = true;
  632.             break;
  633.         case 'm' :
  634.             $this->recordErrors = false;
  635.             $this->overriddenDefaults['recordErrors'] = true;
  636.             break;
  637.         case 'd' :
  638.             $ini = explode('=', $this->cliArgs[($pos + 1)]);
  639.             $this->cliArgs[($pos + 1)] = '';
  640.             if (isset($ini[1]) === true) {
  641.                 ini_set($ini[0], $ini[1]);
  642.             } else {
  643.                 ini_set($ini[0], true);
  644.             }
  645.             break;
  646.         case 'n' :
  647.             if (isset($this->overriddenDefaults['warningSeverity']) === false) {
  648.                 $this->warningSeverity = 0;
  649.                 $this->overriddenDefaults['warningSeverity'] = true;
  650.             }
  651.             break;
  652.         case 'w' :
  653.             if (isset($this->overriddenDefaults['warningSeverity']) === false) {
  654.                 $this->warningSeverity = $this->errorSeverity;
  655.                 $this->overriddenDefaults['warningSeverity'] = true;
  656.             }
  657.             break;
  658.         default:
  659.             if ($this->dieOnUnknownArg === false) {
  660.                 $unknown       = $this->unknown;
  661.                 $unknown[]     = $arg;
  662.                 $this->unknown = $unknown;
  663.             } else {
  664.                 $this->processUnknownArgument('-'.$arg, $pos);
  665.             }
  666.         }//end switch
  667.  
  668.     }//end processShortArgument()
  669.  
  670.  
  671.     /**
  672.      * Processes a long (--example) command line argument.
  673.      *
  674.      * @param string $arg The command line argument.
  675.      * @param int    $pos The position of the argument on the command line.
  676.      *
  677.      * @return void 
  678.      */
  679.     public function processLongArgument($arg, $pos)
  680.     {
  681.         switch ($arg) {
  682.         case 'help':
  683.             ob_start();
  684.             $this->printUsage();
  685.             $output = ob_get_contents();
  686.             ob_end_clean();
  687.             throw new DeepExitException($output, 0);
  688.         case 'version':
  689.             $output  = 'PHP_CodeSniffer version '.self::VERSION.' ('.self::STABILITY.') ';
  690.             $output .= 'by Squiz (http://www.squiz.net)'.PHP_EOL;
  691.             throw new DeepExitException($output, 0);
  692.         case 'colors':
  693.             if (isset($this->overriddenDefaults['colors']) === true) {
  694.                 break;
  695.             }
  696.  
  697.             $this->colors = true;
  698.             $this->overriddenDefaults['colors'] = true;
  699.             break;
  700.         case 'no-colors':
  701.             if (isset($this->overriddenDefaults['colors']) === true) {
  702.                 break;
  703.             }
  704.  
  705.             $this->colors = false;
  706.             $this->overriddenDefaults['colors'] = true;
  707.             break;
  708.         case 'cache':
  709.             if (isset($this->overriddenDefaults['cache']) === true) {
  710.                 break;
  711.             }
  712.  
  713.             if (defined('PHP_CODESNIFFER_IN_TESTS') === false) {
  714.                 $this->cache = true;
  715.                 $this->overriddenDefaults['cache'] = true;
  716.             }
  717.             break;
  718.         case 'no-cache':
  719.             if (isset($this->overriddenDefaults['cache']) === true) {
  720.                 break;
  721.             }
  722.  
  723.             $this->cache = false;
  724.             $this->overriddenDefaults['cache'] = true;
  725.             break;
  726.         case 'ignore-annotations':
  727.             if (isset($this->overriddenDefaults['annotations']) === true) {
  728.                 break;
  729.             }
  730.  
  731.             $this->annotations = false;
  732.             $this->overriddenDefaults['annotations'] = true;
  733.             break;
  734.         case 'config-set':
  735.             if (isset($this->cliArgs[($pos + 1)]) === false
  736.                 || isset($this->cliArgs[($pos + 2)]) === false
  737.             ) {
  738.                 $error  = 'ERROR: Setting a config option requires a name and value'.PHP_EOL.PHP_EOL;
  739.                 $error .= $this->printShortUsage(true);
  740.                 throw new DeepExitException($error, 3);
  741.             }
  742.  
  743.             $key     = $this->cliArgs[($pos + 1)];
  744.             $value   = $this->cliArgs[($pos + 2)];
  745.             $current = self::getConfigData($key);
  746.  
  747.             try {
  748.                 $this->setConfigData($key, $value);
  749.             } catch (\Exception $e) {
  750.                 throw new DeepExitException($e->getMessage().PHP_EOL, 3);
  751.             }
  752.  
  753.             $output = 'Using config file: '.self::$configDataFile.PHP_EOL.PHP_EOL;
  754.  
  755.             if ($current === null) {
  756.                 $output .= "Config value \"$key\" added successfully".PHP_EOL;
  757.             } else {
  758.                 $output .= "Config value \"$key\" updated successfully; old value was \"$current\"".PHP_EOL;
  759.             }
  760.             throw new DeepExitException($output, 0);
  761.         case 'config-delete':
  762.             if (isset($this->cliArgs[($pos + 1)]) === false) {
  763.                 $error  = 'ERROR: Deleting a config option requires the name of the option'.PHP_EOL.PHP_EOL;
  764.                 $error .= $this->printShortUsage(true);
  765.                 throw new DeepExitException($error, 3);
  766.             }
  767.  
  768.             $output = 'Using config file: '.self::$configDataFile.PHP_EOL.PHP_EOL;
  769.  
  770.             $key     = $this->cliArgs[($pos + 1)];
  771.             $current = self::getConfigData($key);
  772.             if ($current === null) {
  773.                 $output .= "Config value \"$key\" has not been set".PHP_EOL;
  774.             } else {
  775.                 try {
  776.                     $this->setConfigData($key, null);
  777.                 } catch (\Exception $e) {
  778.                     throw new DeepExitException($e->getMessage().PHP_EOL, 3);
  779.                 }
  780.  
  781.                 $output .= "Config value \"$key\" removed successfully; old value was \"$current\"".PHP_EOL;
  782.             }
  783.             throw new DeepExitException($output, 0);
  784.         case 'config-show':
  785.             ob_start();
  786.             $data = self::getAllConfigData();
  787.             echo 'Using config file: '.self::$configDataFile.PHP_EOL.PHP_EOL;
  788.             $this->printConfigData($data);
  789.             $output = ob_get_contents();
  790.             ob_end_clean();
  791.             throw new DeepExitException($output, 0);
  792.         case 'runtime-set':
  793.             if (isset($this->cliArgs[($pos + 1)]) === false
  794.                 || isset($this->cliArgs[($pos + 2)]) === false
  795.             ) {
  796.                 $error  = 'ERROR: Setting a runtime config option requires a name and value'.PHP_EOL.PHP_EOL;
  797.                 $error .= $this->printShortUsage(true);
  798.                 throw new DeepExitException($error, 3);
  799.             }
  800.  
  801.             $key   = $this->cliArgs[($pos + 1)];
  802.             $value = $this->cliArgs[($pos + 2)];
  803.             $this->cliArgs[($pos + 1)] = '';
  804.             $this->cliArgs[($pos + 2)] = '';
  805.             self::setConfigData($key, $value, true);
  806.             break;
  807.         default:
  808.             if (substr($arg, 0, 7) === 'sniffs=') {
  809.                 if (isset($this->overriddenDefaults['sniffs']) === true) {
  810.                     break;
  811.                 }
  812.  
  813.                 $sniffs = explode(',', substr($arg, 7));
  814.                 foreach ($sniffs as $sniff) {
  815.                     if (substr_count($sniff, '.') !== 2) {
  816.                         $error  = 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL;
  817.                         $error .= $this->printShortUsage(true);
  818.                         throw new DeepExitException($error, 3);
  819.                     }
  820.                 }
  821.  
  822.                 $this->sniffs = $sniffs;
  823.                 $this->overriddenDefaults['sniffs'] = true;
  824.             } else if (substr($arg, 0, 8) === 'exclude=') {
  825.                 if (isset($this->overriddenDefaults['exclude']) === true) {
  826.                     break;
  827.                 }
  828.  
  829.                 $sniffs = explode(',', substr($arg, 8));
  830.                 foreach ($sniffs as $sniff) {
  831.                     if (substr_count($sniff, '.') !== 2) {
  832.                         $error  = 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL;
  833.                         $error .= $this->printShortUsage(true);
  834.                         throw new DeepExitException($error, 3);
  835.                     }
  836.                 }
  837.  
  838.                 $this->exclude = $sniffs;
  839.                 $this->overriddenDefaults['exclude'] = true;
  840.             } else if (defined('PHP_CODESNIFFER_IN_TESTS') === false
  841.                 && substr($arg, 0, 6) === 'cache='
  842.             ) {
  843.                 if ((isset($this->overriddenDefaults['cache']) === true
  844.                     && $this->cache === false)
  845.                     || isset($this->overriddenDefaults['cacheFile']) === true
  846.                 ) {
  847.                     break;
  848.                 }
  849.  
  850.                 // Turn caching on.
  851.                 $this->cache = true;
  852.                 $this->overriddenDefaults['cache'] = true;
  853.  
  854.                 $this->cacheFile = Util\Common::realpath(substr($arg, 6));
  855.  
  856.                 // It may not exist and return false instead.
  857.                 if ($this->cacheFile === false) {
  858.                     $this->cacheFile = substr($arg, 6);
  859.  
  860.                     $dir = dirname($this->cacheFile);
  861.                     if (is_dir($dir) === false) {
  862.                         $error  = 'ERROR: The specified cache file path "'.$this->cacheFile.'" points to a non-existent directory'.PHP_EOL.PHP_EOL;
  863.                         $error .= $this->printShortUsage(true);
  864.                         throw new DeepExitException($error, 3);
  865.                     }
  866.  
  867.                     if ($dir === '.') {
  868.                         // Passed cache file is a file in the current directory.
  869.                         $this->cacheFile = getcwd().'/'.basename($this->cacheFile);
  870.                     } else {
  871.                         if ($dir{0} === '/') {
  872.                             // An absolute path.
  873.                             $dir = Util\Common::realpath($dir);
  874.                         } else {
  875.                             $dir = Util\Common::realpath(getcwd().'/'.$dir);
  876.                         }
  877.  
  878.                         if ($dir !== false) {
  879.                             // Cache file path is relative.
  880.                             $this->cacheFile = $dir.'/'.basename($this->cacheFile);
  881.                         }
  882.                     }
  883.                 }//end if
  884.  
  885.                 $this->overriddenDefaults['cacheFile'] = true;
  886.  
  887.                 if (is_dir($this->cacheFile) === true) {
  888.                     $error  = 'ERROR: The specified cache file path "'.$this->cacheFile.'" is a directory'.PHP_EOL.PHP_EOL;
  889.                     $error .= $this->printShortUsage(true);
  890.                     throw new DeepExitException($error, 3);
  891.                 }
  892.             } else if (substr($arg, 0, 10) === 'bootstrap=') {
  893.                 $files     = explode(',', substr($arg, 10));
  894.                 $bootstrap = array();
  895.                 foreach ($files as $file) {
  896.                     $path = Util\Common::realpath($file);
  897.                     if ($path === false) {
  898.                         $error  = 'ERROR: The specified bootstrap file "'.$file.'" does not exist'.PHP_EOL.PHP_EOL;
  899.                         $error .= $this->printShortUsage(true);
  900.                         throw new DeepExitException($error, 3);
  901.                     }
  902.  
  903.                     $bootstrap[] = $path;
  904.                 }
  905.  
  906.                 $this->bootstrap = array_merge($this->bootstrap, $bootstrap);
  907.                 $this->overriddenDefaults['bootstrap'] = true;
  908.             } else if (substr($arg, 0, 10) === 'file-list=') {
  909.                 $fileList = substr($arg, 10);
  910.                 $path     = Util\Common::realpath($fileList);
  911.                 if ($path === false) {
  912.                     $error  = 'ERROR: The specified file list "'.$fileList.'" does not exist'.PHP_EOL.PHP_EOL;
  913.                     $error .= $this->printShortUsage(true);
  914.                     throw new DeepExitException($error, 3);
  915.                 }
  916.  
  917.                 $files = file($path);
  918.                 foreach ($files as $inputFile) {
  919.                     $inputFile = trim($inputFile);
  920.  
  921.                     // Skip empty lines.
  922.                     if ($inputFile === '') {
  923.                         continue;
  924.                     }
  925.  
  926.                     $this->processFilePath($inputFile);
  927.                 }
  928.             } else if (substr($arg, 0, 11) === 'stdin-path=') {
  929.                 if (isset($this->overriddenDefaults['stdinPath']) === true) {
  930.                     break;
  931.                 }
  932.  
  933.                 $this->stdinPath = Util\Common::realpath(substr($arg, 11));
  934.  
  935.                 // It may not exist and return false instead, so use whatever they gave us.
  936.                 if ($this->stdinPath === false) {
  937.                     $this->stdinPath = trim(substr($arg, 11));
  938.                 }
  939.  
  940.                 $this->overriddenDefaults['stdinPath'] = true;
  941.             } else if (PHP_CODESNIFFER_CBF === false && substr($arg, 0, 12) === 'report-file=') {
  942.                 if (isset($this->overriddenDefaults['reportFile']) === true) {
  943.                     break;
  944.                 }
  945.  
  946.                 $this->reportFile = Util\Common::realpath(substr($arg, 12));
  947.  
  948.                 // It may not exist and return false instead.
  949.                 if ($this->reportFile === false) {
  950.                     $this->reportFile = substr($arg, 12);
  951.  
  952.                     $dir = dirname($this->reportFile);
  953.                     if (is_dir($dir) === false) {
  954.                         $error  = 'ERROR: The specified report file path "'.$this->reportFile.'" points to a non-existent directory'.PHP_EOL.PHP_EOL;
  955.                         $error .= $this->printShortUsage(true);
  956.                         throw new DeepExitException($error, 3);
  957.                     }
  958.  
  959.                     if ($dir === '.') {
  960.                         // Passed report file is a file in the current directory.
  961.                         $this->reportFile = getcwd().'/'.basename($this->reportFile);
  962.                     } else {
  963.                         if ($dir{0} === '/') {
  964.                             // An absolute path.
  965.                             $dir = Util\Common::realpath($dir);
  966.                         } else {
  967.                             $dir = Util\Common::realpath(getcwd().'/'.$dir);
  968.                         }
  969.  
  970.                         if ($dir !== false) {
  971.                             // Report file path is relative.
  972.                             $this->reportFile = $dir.'/'.basename($this->reportFile);
  973.                         }
  974.                     }
  975.                 }//end if
  976.  
  977.                 $this->overriddenDefaults['reportFile'] = true;
  978.  
  979.                 if (is_dir($this->reportFile) === true) {
  980.                     $error  = 'ERROR: The specified report file path "'.$this->reportFile.'" is a directory'.PHP_EOL.PHP_EOL;
  981.                     $error .= $this->printShortUsage(true);
  982.                     throw new DeepExitException($error, 3);
  983.                 }
  984.             } else if (substr($arg, 0, 13) === 'report-width=') {
  985.                 if (isset($this->overriddenDefaults['reportWidth']) === true) {
  986.                     break;
  987.                 }
  988.  
  989.                 $this->reportWidth = substr($arg, 13);
  990.                 $this->overriddenDefaults['reportWidth'] = true;
  991.             } else if (substr($arg, 0, 9) === 'basepath=') {
  992.                 if (isset($this->overriddenDefaults['basepath']) === true) {
  993.                     break;
  994.                 }
  995.  
  996.                 $this->basepath = Util\Common::realpath(substr($arg, 9));
  997.  
  998.                 // It may not exist and return false instead.
  999.                 if ($this->basepath === false) {
  1000.                     $this->basepath = substr($arg, 9);
  1001.                 }
  1002.  
  1003.                 $this->overriddenDefaults['basepath'] = true;
  1004.  
  1005.                 if (is_dir($this->basepath) === false) {
  1006.                     $error  = 'ERROR: The specified basepath "'.$this->basepath.'" points to a non-existent directory'.PHP_EOL.PHP_EOL;
  1007.                     $error .= $this->printShortUsage(true);
  1008.                     throw new DeepExitException($error, 3);
  1009.                 }
  1010.             } else if ((substr($arg, 0, 7) === 'report=' || substr($arg, 0, 7) === 'report-')) {
  1011.                 $reports = array();
  1012.  
  1013.                 if ($arg[6] === '-') {
  1014.                     // This is a report with file output.
  1015.                     $split = strpos($arg, '=');
  1016.                     if ($split === false) {
  1017.                         $report = substr($arg, 7);
  1018.                         $output = null;
  1019.                     } else {
  1020.                         $report = substr($arg, 7, ($split - 7));
  1021.                         $output = substr($arg, ($split + 1));
  1022.                         if ($output === false) {
  1023.                             $output = null;
  1024.                         } else {
  1025.                             $dir = dirname($output);
  1026.                             if ($dir === '.') {
  1027.                                 // Passed report file is a filename in the current directory.
  1028.                                 $output = getcwd().'/'.basename($output);
  1029.                             } else {
  1030.                                 if ($dir{0} === '/') {
  1031.                                     // An absolute path.
  1032.                                     $dir = Util\Common::realpath($dir);
  1033.                                 } else {
  1034.                                     $dir = Util\Common::realpath(getcwd().'/'.$dir);
  1035.                                 }
  1036.  
  1037.                                 if ($dir !== false) {
  1038.                                     // Report file path is relative.
  1039.                                     $output = $dir.'/'.basename($output);
  1040.                                 }
  1041.                             }
  1042.                         }//end if
  1043.                     }//end if
  1044.  
  1045.                     $reports[$report] = $output;
  1046.                 } else {
  1047.                     // This is a single report.
  1048.                     if (isset($this->overriddenDefaults['reports']) === true) {
  1049.                         break;
  1050.                     }
  1051.  
  1052.                     $reportNames = explode(',', substr($arg, 7));
  1053.                     foreach ($reportNames as $report) {
  1054.                         $reports[$report] = null;
  1055.                     }
  1056.                 }//end if
  1057.  
  1058.                 // Remove the default value so the CLI value overrides it.
  1059.                 if (isset($this->overriddenDefaults['reports']) === false) {
  1060.                     $this->reports = $reports;
  1061.                 } else {
  1062.                     $this->reports = array_merge($this->reports, $reports);
  1063.                 }
  1064.  
  1065.                 $this->overriddenDefaults['reports'] = true;
  1066.             } else if (substr($arg, 0, 7) === 'filter=') {
  1067.                 if (isset($this->overriddenDefaults['filter']) === true) {
  1068.                     break;
  1069.                 }
  1070.  
  1071.                 $this->filter = substr($arg, 7);
  1072.                 $this->overriddenDefaults['filter'] = true;
  1073.             } else if (substr($arg, 0, 9) === 'standard=') {
  1074.                 $standards = trim(substr($arg, 9));
  1075.                 if ($standards !== '') {
  1076.                     $this->standards = explode(',', $standards);
  1077.                 }
  1078.  
  1079.                 $this->overriddenDefaults['standards'] = true;
  1080.             } else if (substr($arg, 0, 11) === 'extensions=') {
  1081.                 if (isset($this->overriddenDefaults['extensions']) === true) {
  1082.                     break;
  1083.                 }
  1084.  
  1085.                 $extensions    = explode(',', substr($arg, 11));
  1086.                 $newExtensions = array();
  1087.                 foreach ($extensions as $ext) {
  1088.                     $slash = strpos($ext, '/');
  1089.                     if ($slash !== false) {
  1090.                         // They specified the tokenizer too.
  1091.                         list($ext, $tokenizer) = explode('/', $ext);
  1092.                         $newExtensions[$ext]   = strtoupper($tokenizer);
  1093.                         continue;
  1094.                     }
  1095.  
  1096.                     if (isset($this->extensions[$ext]) === true) {
  1097.                         $newExtensions[$ext] = $this->extensions[$ext];
  1098.                     } else {
  1099.                         $newExtensions[$ext] = 'PHP';
  1100.                     }
  1101.                 }
  1102.  
  1103.                 $this->extensions = $newExtensions;
  1104.                 $this->overriddenDefaults['extensions'] = true;
  1105.             } else if (substr($arg, 0, 7) === 'suffix=') {
  1106.                 if (isset($this->overriddenDefaults['suffix']) === true) {
  1107.                     break;
  1108.                 }
  1109.  
  1110.                 $this->suffix = substr($arg, 7);
  1111.                 $this->overriddenDefaults['suffix'] = true;
  1112.             } else if (substr($arg, 0, 9) === 'parallel=') {
  1113.                 if (isset($this->overriddenDefaults['parallel']) === true) {
  1114.                     break;
  1115.                 }
  1116.  
  1117.                 $this->parallel = max((int) substr($arg, 9), 1);
  1118.                 $this->overriddenDefaults['parallel'] = true;
  1119.             } else if (substr($arg, 0, 9) === 'severity=') {
  1120.                 $this->errorSeverity   = (int) substr($arg, 9);
  1121.                 $this->warningSeverity = $this->errorSeverity;
  1122.                 if (isset($this->overriddenDefaults['errorSeverity']) === false) {
  1123.                     $this->overriddenDefaults['errorSeverity'] = true;
  1124.                 }
  1125.  
  1126.                 if (isset($this->overriddenDefaults['warningSeverity']) === false) {
  1127.                     $this->overriddenDefaults['warningSeverity'] = true;
  1128.                 }
  1129.             } else if (substr($arg, 0, 15) === 'error-severity=') {
  1130.                 if (isset($this->overriddenDefaults['errorSeverity']) === true) {
  1131.                     break;
  1132.                 }
  1133.  
  1134.                 $this->errorSeverity = (int) substr($arg, 15);
  1135.                 $this->overriddenDefaults['errorSeverity'] = true;
  1136.             } else if (substr($arg, 0, 17) === 'warning-severity=') {
  1137.                 if (isset($this->overriddenDefaults['warningSeverity']) === true) {
  1138.                     break;
  1139.                 }
  1140.  
  1141.                 $this->warningSeverity = (int) substr($arg, 17);
  1142.                 $this->overriddenDefaults['warningSeverity'] = true;
  1143.             } else if (substr($arg, 0, 7) === 'ignore=') {
  1144.                 if (isset($this->overriddenDefaults['ignored']) === true) {
  1145.                     break;
  1146.                 }
  1147.  
  1148.                 // Split the ignore string on commas, unless the comma is escaped
  1149.                 // using 1 or 3 slashes (\, or \\\,).
  1150.                 $patterns = preg_split(
  1151.                     '/(?<=(?<!\\\\)\\\\\\\\),|(?<!\\\\),/',
  1152.                     substr($arg, 7)
  1153.                 );
  1154.  
  1155.                 $ignored = array();
  1156.                 foreach ($patterns as $pattern) {
  1157.                     $pattern = trim($pattern);
  1158.                     if ($pattern === '') {
  1159.                         continue;
  1160.                     }
  1161.  
  1162.                     $ignored[$pattern] = 'absolute';
  1163.                 }
  1164.  
  1165.                 $this->ignored = $ignored;
  1166.                 $this->overriddenDefaults['ignored'] = true;
  1167.             } else if (substr($arg, 0, 10) === 'generator='
  1168.                 && PHP_CODESNIFFER_CBF === false
  1169.             ) {
  1170.                 if (isset($this->overriddenDefaults['generator']) === true) {
  1171.                     break;
  1172.                 }
  1173.  
  1174.                 $this->generator = substr($arg, 10);
  1175.                 $this->overriddenDefaults['generator'] = true;
  1176.             } else if (substr($arg, 0, 9) === 'encoding=') {
  1177.                 if (isset($this->overriddenDefaults['encoding']) === true) {
  1178.                     break;
  1179.                 }
  1180.  
  1181.                 $this->encoding = strtolower(substr($arg, 9));
  1182.                 $this->overriddenDefaults['encoding'] = true;
  1183.             } else if (substr($arg, 0, 10) === 'tab-width=') {
  1184.                 if (isset($this->overriddenDefaults['tabWidth']) === true) {
  1185.                     break;
  1186.                 }
  1187.  
  1188.                 $this->tabWidth = (int) substr($arg, 10);
  1189.                 $this->overriddenDefaults['tabWidth'] = true;
  1190.             } else {
  1191.                 if ($this->dieOnUnknownArg === false) {
  1192.                     $eqPos = strpos($arg, '=');
  1193.                     try {
  1194.                         if ($eqPos === false) {
  1195.                             $this->values[$arg] = $arg;
  1196.                         } else {
  1197.                             $value = substr($arg, ($eqPos + 1));
  1198.                             $arg   = substr($arg, 0, $eqPos);
  1199.                             $this->values[$arg] = $value;
  1200.                         }
  1201.                     } catch (RuntimeException $e) {
  1202.                         // Value is not valid, so just ignore it.
  1203.                     }
  1204.                 } else {
  1205.                     $this->processUnknownArgument('--'.$arg, $pos);
  1206.                 }
  1207.             }//end if
  1208.  
  1209.             break;
  1210.         }//end switch
  1211.  
  1212.     }//end processLongArgument()
  1213.  
  1214.  
  1215.     /**
  1216.      * Processes an unknown command line argument.
  1217.      *
  1218.      * Assumes all unknown arguments are files and folders to check.
  1219.      *
  1220.      * @param string $arg The command line argument.
  1221.      * @param int    $pos The position of the argument on the command line.
  1222.      *
  1223.      * @return void 
  1224.      */
  1225.     public function processUnknownArgument($arg, $pos)
  1226.     {
  1227.         // We don't know about any additional switches; just files.
  1228.         if ($arg{0} === '-') {
  1229.             if ($this->dieOnUnknownArg === false) {
  1230.                 return;
  1231.             }
  1232.  
  1233.             $error  = "ERROR: option \"$arg\" not known".PHP_EOL.PHP_EOL;
  1234.             $error .= $this->printShortUsage(true);
  1235.             throw new DeepExitException($error, 3);
  1236.         }
  1237.  
  1238.         $this->processFilePath($arg);
  1239.  
  1240.     }//end processUnknownArgument()
  1241.  
  1242.  
  1243.     /**
  1244.      * Processes a file path and add it to the file list.
  1245.      *
  1246.      * @param string $path The path to the file to add.
  1247.      *
  1248.      * @return void 
  1249.      */
  1250.     public function processFilePath($path)
  1251.     {
  1252.         // If we are processing STDIN, don't record any files to check.
  1253.         if ($this->stdin === true) {
  1254.             return;
  1255.         }
  1256.  
  1257.         $file = Util\Common::realpath($path);
  1258.         if (file_exists($file) === false) {
  1259.             if ($this->dieOnUnknownArg === false) {
  1260.                 return;
  1261.             }
  1262.  
  1263.             $error  = 'ERROR: The file "'.$path.'" does not exist.'.PHP_EOL.PHP_EOL;
  1264.             $error .= $this->printShortUsage(true);
  1265.             throw new DeepExitException($error, 3);
  1266.         } else {
  1267.             $files       = $this->files;
  1268.             $files[]     = $file;
  1269.             $this->files = $files;
  1270.             $this->overriddenDefaults['files'] = true;
  1271.         }
  1272.  
  1273.     }//end processFilePath()
  1274.  
  1275.  
  1276.     /**
  1277.      * Prints out the usage information for this script.
  1278.      *
  1279.      * @return void 
  1280.      */
  1281.     public function printUsage()
  1282.     {
  1283.         echo PHP_EOL;
  1284.  
  1285.         if (PHP_CODESNIFFER_CBF === true) {
  1286.             $this->printPHPCBFUsage();
  1287.         } else {
  1288.             $this->printPHPCSUsage();
  1289.         }
  1290.  
  1291.         echo PHP_EOL;
  1292.  
  1293.     }//end printUsage()
  1294.  
  1295.  
  1296.     /**
  1297.      * Prints out the short usage information for this script.
  1298.      *
  1299.      * @param bool $return If TRUE, the usage string is returned
  1300.      *                      instead of output to screen.
  1301.      *
  1302.      * @return string|void
  1303.      */
  1304.     public function printShortUsage($return=false)
  1305.     {
  1306.         if (PHP_CODESNIFFER_CBF === true) {
  1307.             $usage = 'Run "phpcbf --help" for usage information';
  1308.         } else {
  1309.             $usage = 'Run "phpcs --help" for usage information';
  1310.         }
  1311.  
  1312.         $usage .= PHP_EOL.PHP_EOL;
  1313.  
  1314.         if ($return === true) {
  1315.             return $usage;
  1316.         }
  1317.  
  1318.         echo $usage;
  1319.  
  1320.     }//end printShortUsage()
  1321.  
  1322.  
  1323.     /**
  1324.      * Prints out the usage information for PHPCS.
  1325.      *
  1326.      * @return void 
  1327.      */
  1328.     public function printPHPCSUsage()
  1329.     {
  1330.         echo 'Usage: phpcs [-nwlsaepqvi] [-d key[=value]] [--colors] [--no-colors]'.PHP_EOL;
  1331.         echo '  [--cache[=<cacheFile>]] [--no-cache] [--tab-width=<tabWidth>]'.PHP_EOL;
  1332.         echo '  [--report=<report>] [--report-file=<reportFile>] [--report-<report>=<reportFile>]'.PHP_EOL;
  1333.         echo '  [--report-width=<reportWidth>] [--basepath=<basepath>] [--bootstrap=<bootstrap>]'.PHP_EOL;
  1334.         echo '  [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL;
  1335.         echo '  [--runtime-set key value] [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL;
  1336.         echo '  [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>]'.PHP_EOL;
  1337.         echo '  [--encoding=<encoding>] [--parallel=<processes>] [--generator=<generator>]'.PHP_EOL;
  1338.         echo '  [--extensions=<extensions>] [--ignore=<patterns>] [--ignore-annotations]'.PHP_EOL;
  1339.         echo '  [--stdin-path=<stdinPath>] [--file-list=<fileList>] <file> - ...'.PHP_EOL;
  1340.         echo PHP_EOL;
  1341.         echo ' -     Check STDIN instead of local files and directories'.PHP_EOL;
  1342.         echo ' -n    Do not print warnings (shortcut for --warning-severity=0)'.PHP_EOL;
  1343.         echo ' -w    Print both warnings and errors (this is the default)'.PHP_EOL;
  1344.         echo ' -l    Local directory only, no recursion'.PHP_EOL;
  1345.         echo ' -s    Show sniff codes in all reports'.PHP_EOL;
  1346.         echo ' -a    Run interactively'.PHP_EOL;
  1347.         echo ' -e    Explain a standard by showing the sniffs it includes'.PHP_EOL;
  1348.         echo ' -p    Show progress of the run'.PHP_EOL;
  1349.         echo ' -q    Quiet mode; disables progress and verbose output'.PHP_EOL;
  1350.         echo ' -m    Stop error messages from being recorded'.PHP_EOL;
  1351.         echo '       (saves a lot of memory, but stops many reports from being used)'.PHP_EOL;
  1352.         echo ' -v    Print processed files'.PHP_EOL;
  1353.         echo ' -vv   Print ruleset and token output'.PHP_EOL;
  1354.         echo ' -vvv  Print sniff processing information'.PHP_EOL;
  1355.         echo ' -i    Show a list of installed coding standards'.PHP_EOL;
  1356.         echo ' -d    Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL;
  1357.         echo PHP_EOL;
  1358.         echo ' --help                Print this help message'.PHP_EOL;
  1359.         echo ' --version             Print version information'.PHP_EOL;
  1360.         echo ' --colors              Use colors in output'.PHP_EOL;
  1361.         echo ' --no-colors           Do not use colors in output (this is the default)'.PHP_EOL;
  1362.         echo ' --cache               Cache results between runs'.PHP_EOL;
  1363.         echo ' --no-cache            Do not cache results between runs (this is the default)'.PHP_EOL;
  1364.         echo ' --ignore-annotations  Ignore all @codingStandard annotations in code comments'.PHP_EOL;
  1365.         echo PHP_EOL;
  1366.         echo ' <cacheFile>    Use a specific file for caching (uses a temporary file by default)'.PHP_EOL;
  1367.         echo ' <basepath>     A path to strip from the front of file paths inside reports'.PHP_EOL;
  1368.         echo ' <bootstrap>    A comma separated list of files to run before processing begins'.PHP_EOL;
  1369.         echo ' <file>         One or more files and/or directories to check'.PHP_EOL;
  1370.         echo ' <fileList>     A file containing a list of files and/or directories to check (one per line)'.PHP_EOL;
  1371.         echo ' <encoding>     The encoding of the files being checked (default is utf-8)'.PHP_EOL;
  1372.         echo ' <extensions>   A comma separated list of file extensions to check'.PHP_EOL;
  1373.         echo '                The type of the file can be specified using: ext/type'.PHP_EOL;
  1374.         echo '                e.g., module/php,es/js'.PHP_EOL;
  1375.         echo ' <generator>    Uses either the "HTML", "Markdown" or "Text" generator'.PHP_EOL;
  1376.         echo '                (forces documentation generation instead of checking)'.PHP_EOL;
  1377.         echo ' <patterns>     A comma separated list of patterns to ignore files and directories'.PHP_EOL;
  1378.         echo ' <processes>    How many files should be checked simultaneously (default is 1)'.PHP_EOL;
  1379.         echo ' <report>       Print either the "full", "xml", "checkstyle", "csv"'.PHP_EOL;
  1380.         echo '                "json", "junit", "emacs", "source", "summary", "diff"'.PHP_EOL;
  1381.         echo '                "svnblame", "gitblame", "hgblame" or "notifysend" report'.PHP_EOL;
  1382.         echo '                (the "full" report is printed by default)'.PHP_EOL;
  1383.         echo ' <reportFile>   Write the report to the specified file path'.PHP_EOL;
  1384.         echo ' <reportWidth>  How many columns wide screen reports should be printed'.PHP_EOL;
  1385.         echo '                or set to "auto" to use current screen width, where supported'.PHP_EOL;
  1386.         echo ' <severity>     The minimum severity required to display an error or warning'.PHP_EOL;
  1387.         echo ' <sniffs>       A comma separated list of sniff codes to include or exclude from checking'.PHP_EOL;
  1388.         echo '                (all sniffs must be part of the specified standard)'.PHP_EOL;
  1389.         echo ' <standard>     The name or path of the coding standard to use'.PHP_EOL;
  1390.         echo ' <stdinPath>    If processing STDIN, the file path that STDIN will be processed as'.PHP_EOL;
  1391.         echo ' <tabWidth>     The number of spaces each tab represents'.PHP_EOL;
  1392.  
  1393.     }//end printPHPCSUsage()
  1394.  
  1395.  
  1396.     /**
  1397.      * Prints out the usage information for PHPCBF.
  1398.      *
  1399.      * @return void 
  1400.      */
  1401.     public function printPHPCBFUsage()
  1402.     {
  1403.         echo 'Usage: phpcbf [-nwli] [-d key[=value]] [--ignore-annotations] [--bootstrap=<bootstrap>]'.PHP_EOL;
  1404.         echo '  [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>] [--suffix=<suffix>]'.PHP_EOL;
  1405.         echo '  [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL;
  1406.         echo '  [--tab-width=<tabWidth>] [--encoding=<encoding>] [--parallel=<processes>]'.PHP_EOL;
  1407.         echo '  [--basepath=<basepath>] [--extensions=<extensions>] [--ignore=<patterns>]'.PHP_EOL;
  1408.         echo '  [--stdin-path=<stdinPath>] [--file-list=<fileList>] <file> - ...'.PHP_EOL;
  1409.         echo PHP_EOL;
  1410.         echo ' -     Fix STDIN instead of local files and directories'.PHP_EOL;
  1411.         echo ' -n    Do not fix warnings (shortcut for --warning-severity=0)'.PHP_EOL;
  1412.         echo ' -w    Fix both warnings and errors (on by default)'.PHP_EOL;
  1413.         echo ' -l    Local directory only, no recursion'.PHP_EOL;
  1414.         echo ' -p    Show progress of the run'.PHP_EOL;
  1415.         echo ' -q    Quiet mode; disables progress and verbose output'.PHP_EOL;
  1416.         echo ' -v    Print processed files'.PHP_EOL;
  1417.         echo ' -vv   Print ruleset and token output'.PHP_EOL;
  1418.         echo ' -vvv  Print sniff processing information'.PHP_EOL;
  1419.         echo ' -i    Show a list of installed coding standards'.PHP_EOL;
  1420.         echo ' -d    Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL;
  1421.         echo PHP_EOL;
  1422.         echo ' --help                Print this help message'.PHP_EOL;
  1423.         echo ' --version             Print version information'.PHP_EOL;
  1424.         echo ' --ignore-annotations  Ignore all @codingStandard annotations in code comments'.PHP_EOL;
  1425.         echo PHP_EOL;
  1426.         echo ' <basepath>    A path to strip from the front of file paths inside reports'.PHP_EOL;
  1427.         echo ' <bootstrap>   A comma separated list of files to run before processing begins'.PHP_EOL;
  1428.         echo ' <file>        One or more files and/or directories to fix'.PHP_EOL;
  1429.         echo ' <fileList>    A file containing a list of files and/or directories to fix (one per line)'.PHP_EOL;
  1430.         echo ' <encoding>    The encoding of the files being fixed (default is utf-8)'.PHP_EOL;
  1431.         echo ' <extensions>  A comma separated list of file extensions to fix'.PHP_EOL;
  1432.         echo '               The type of the file can be specified using: ext/type'.PHP_EOL;
  1433.         echo '               e.g., module/php,es/js'.PHP_EOL;
  1434.         echo ' <patterns>    A comma separated list of patterns to ignore files and directories'.PHP_EOL;
  1435.         echo ' <processes>   How many files should be fixed simultaneously (default is 1)'.PHP_EOL;
  1436.         echo ' <severity>    The minimum severity required to fix an error or warning'.PHP_EOL;
  1437.         echo ' <sniffs>      A comma separated list of sniff codes to include or exclude from fixing'.PHP_EOL;
  1438.         echo '               (all sniffs must be part of the specified standard)'.PHP_EOL;
  1439.         echo ' <standard>    The name or path of the coding standard to use'.PHP_EOL;
  1440.         echo ' <stdinPath>   If processing STDIN, the file path that STDIN will be processed as'.PHP_EOL;
  1441.         echo ' <suffix>      Write modified files to a filename using this suffix'.PHP_EOL;
  1442.         echo '               ("diff" and "patch" are not used in this mode)'.PHP_EOL;
  1443.         echo ' <tabWidth>    The number of spaces each tab represents'.PHP_EOL;
  1444.  
  1445.     }//end printPHPCBFUsage()
  1446.  
  1447.  
  1448.     /**
  1449.      * Get a single config value.
  1450.      *
  1451.      * @param string $key The name of the config value.
  1452.      *
  1453.      * @return string|null
  1454.      * @see    setConfigData()
  1455.      * @see    getAllConfigData()
  1456.      */
  1457.     public static function getConfigData($key)
  1458.     {
  1459.         $phpCodeSnifferConfig = self::getAllConfigData();
  1460.  
  1461.         if ($phpCodeSnifferConfig === null) {
  1462.             return null;
  1463.         }
  1464.  
  1465.         if (isset($phpCodeSnifferConfig[$key]) === false) {
  1466.             return null;
  1467.         }
  1468.  
  1469.         return $phpCodeSnifferConfig[$key];
  1470.  
  1471.     }//end getConfigData()
  1472.  
  1473.  
  1474.     /**
  1475.      * Get the path to an executable utility.
  1476.      *
  1477.      * @param string $name The name of the executable utility.
  1478.      *
  1479.      * @return string|null
  1480.      * @see    getConfigData()
  1481.      */
  1482.     public static function getExecutablePath($name)
  1483.     {
  1484.         $data = self::getConfigData($name.'_path');
  1485.         if ($data !== null) {
  1486.             return $data;
  1487.         }
  1488.  
  1489.         if (array_key_exists($name, self::$executablePaths) === true) {
  1490.             return self::$executablePaths[$name];
  1491.         }
  1492.  
  1493.         if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
  1494.             $cmd = 'where '.escapeshellarg($name).' 2> nul';
  1495.         } else {
  1496.             $cmd = 'which '.escapeshellarg($name).' 2> /dev/null';
  1497.         }
  1498.  
  1499.         $result = exec($cmd, $output, $retVal);
  1500.         if ($retVal !== 0) {
  1501.             $result = null;
  1502.         }
  1503.  
  1504.         self::$executablePaths[$name] = $result;
  1505.         return $result;
  1506.  
  1507.     }//end getExecutablePath()
  1508.  
  1509.  
  1510.     /**
  1511.      * Set a single config value.
  1512.      *
  1513.      * @param string      $key   The name of the config value.
  1514.      * @param string|null$value The value to set. If null, the config
  1515.      *                            entry is deleted, reverting it to the
  1516.      *                            default value.
  1517.      * @param boolean     $temp  Set this config data temporarily for this
  1518.      *                            script run. This will not write the config
  1519.      *                            data to the config file.
  1520.      *
  1521.      * @return bool 
  1522.      * @see    getConfigData()
  1523.      * @throws RuntimeException If the config file can not be written.
  1524.      */
  1525.     public static function setConfigData($key, $value, $temp=false)
  1526.     {
  1527.         if ($temp === false) {
  1528.             $path = '';
  1529.             if (is_callable('\Phar::running') === true) {
  1530.                 $path = \Phar::running(false);
  1531.             }
  1532.  
  1533.             if ($path !== '') {
  1534.                 $configFile = dirname($path).'/CodeSniffer.conf';
  1535.             } else {
  1536.                 $configFile = dirname(__DIR__).'/CodeSniffer.conf';
  1537.                 if (is_file($configFile) === false
  1538.                     && strpos('@data_dir@', '@data_dir') === false
  1539.                 ) {
  1540.                     // If data_dir was replaced, this is a PEAR install and we can
  1541.                     // use the PEAR data dir to store the conf file.
  1542.                     $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf';
  1543.                 }
  1544.             }
  1545.  
  1546.             if (is_file($configFile) === true
  1547.                 && is_writable($configFile) === false
  1548.             ) {
  1549.                 $error = 'ERROR: Config file '.$configFile.' is not writable'.PHP_EOL.PHP_EOL;
  1550.                 throw new DeepExitException($error, 3);
  1551.             }
  1552.         }//end if
  1553.  
  1554.         $phpCodeSnifferConfig = self::getAllConfigData();
  1555.  
  1556.         if ($value === null) {
  1557.             if (isset($phpCodeSnifferConfig[$key]) === true) {
  1558.                 unset($phpCodeSnifferConfig[$key]);
  1559.             }
  1560.         } else {
  1561.             $phpCodeSnifferConfig[$key] = $value;
  1562.         }
  1563.  
  1564.         if ($temp === false) {
  1565.             $output  = '<'.'?php'."\n".' $phpCodeSnifferConfig = ';
  1566.             $output .= var_export($phpCodeSnifferConfig, true);
  1567.             $output .= "\n?".'>';
  1568.  
  1569.             if (file_put_contents($configFile, $output) === false) {
  1570.                 $error = 'ERROR: Config file '.$configFile.' could not be written'.PHP_EOL.PHP_EOL;
  1571.                 throw new DeepExitException($error, 3);
  1572.             }
  1573.  
  1574.             self::$configDataFile = $configFile;
  1575.         }
  1576.  
  1577.         self::$configData = $phpCodeSnifferConfig;
  1578.  
  1579.         // If the installed paths are being set, make sure all known
  1580.         // standards paths are added to the autoloader.
  1581.         if ($key === 'installed_paths') {
  1582.             $installedStandards = Util\Standards::getInstalledStandardDetails();
  1583.             foreach ($installedStandards as $name => $details) {
  1584.                 Autoload::addSearchPath($details['path'], $details['namespace']);
  1585.             }
  1586.         }
  1587.  
  1588.         return true;
  1589.  
  1590.     }//end setConfigData()
  1591.  
  1592.  
  1593.     /**
  1594.      * Get all config data.
  1595.      *
  1596.      * @return array<string, string>
  1597.      * @see    getConfigData()
  1598.      */
  1599.     public static function getAllConfigData()
  1600.     {
  1601.         if (self::$configData !== null) {
  1602.             return self::$configData;
  1603.         }
  1604.  
  1605.         $path = '';
  1606.         if (is_callable('\Phar::running') === true) {
  1607.             $path = \Phar::running(false);
  1608.         }
  1609.  
  1610.         if ($path !== '') {
  1611.             $configFile = dirname($path).'/CodeSniffer.conf';
  1612.         } else {
  1613.             $configFile = dirname(__DIR__).'/CodeSniffer.conf';
  1614.             if (is_file($configFile) === false
  1615.                 && strpos('@data_dir@', '@data_dir') === false
  1616.             ) {
  1617.                 $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf';
  1618.             }
  1619.         }
  1620.  
  1621.         if (is_file($configFile) === false) {
  1622.             self::$configData = array();
  1623.             return array();
  1624.         }
  1625.  
  1626.         if (is_readable($configFile) === false) {
  1627.             $error = 'ERROR: Config file '.$configFile.' is not readable'.PHP_EOL.PHP_EOL;
  1628.             throw new DeepExitException($error, 3);
  1629.         }
  1630.  
  1631.         include $configFile;
  1632.         self::$configDataFile = $configFile;
  1633.         self::$configData     = $phpCodeSnifferConfig;
  1634.         return self::$configData;
  1635.  
  1636.     }//end getAllConfigData()
  1637.  
  1638.  
  1639.     /**
  1640.      * Prints out the gathered config data.
  1641.      *
  1642.      * @param array $data The config data to print.
  1643.      *
  1644.      * @return void 
  1645.      */
  1646.     public function printConfigData($data)
  1647.     {
  1648.         $max  = 0;
  1649.         $keys = array_keys($data);
  1650.         foreach ($keys as $key) {
  1651.             $len = strlen($key);
  1652.             if (strlen($key) > $max) {
  1653.                 $max = $len;
  1654.             }
  1655.         }
  1656.  
  1657.         if ($max === 0) {
  1658.             return;
  1659.         }
  1660.  
  1661.         $max += 2;
  1662.         ksort($data);
  1663.         foreach ($data as $name => $value) {
  1664.             echo str_pad($name.': ', $max).$value.PHP_EOL;
  1665.         }
  1666.  
  1667.     }//end printConfigData()
  1668.  
  1669.  
  1670. }//end class

Documentation generated on Mon, 11 Mar 2019 15:27:20 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.