License updated to GPLv3

🧲 New features
Custom user role permissions
Employee edit form updated
Employee daily task list
Attendance and employee distribution charts on dashboard
Improvements to company structure and company assets module
Improved tables for displaying data in several modules
Faster data loading (specially for employee module)
Initials based profile pictures
Re-designed login page
Re-designed user profile page
Improvements to filtering
New REST endpoints for employee qualifications

🐛 Bug fixes
Fixed, issue with managers being able to create performance reviews for employees who are not their direct reports
Fixed, issues related to using full profile image instead of using smaller version of profile image
Changing third gender to other
Improvements and fixes for internal frontend data caching
This commit is contained in:
Thilina Pituwala
2020-10-31 19:02:37 +01:00
parent 86b8345505
commit b1df0037db
29343 changed files with 867614 additions and 2191082 deletions

View File

@@ -0,0 +1,13 @@
/tests export-ignore
/CodeSniffer/Standards/Generic/Tests export-ignore
/CodeSniffer/Standards/MySource/Tests export-ignore
/CodeSniffer/Standards/PEAR/Tests export-ignore
/CodeSniffer/Standards/PSR1/Tests export-ignore
/CodeSniffer/Standards/PSR2/Tests export-ignore
/CodeSniffer/Standards/Squiz/Tests export-ignore
/CodeSniffer/Standards/Zend/Tests export-ignore
.travis.yml export-ignore
package.xml export-ignore
phpunit.xml.dist export-ignore
php5-testingConfig.ini export-ignore
php7-testingConfig.ini export-ignore

View File

@@ -0,0 +1,6 @@
/CodeSniffer.conf
/phpcs.xml
/phpunit.xml
.idea/*
/vendor/
composer.lock

View File

@@ -0,0 +1,13 @@
Contributing
-------------
Before you contribute code to PHP\_CodeSniffer, please make sure it conforms to the PHPCS coding standard and that the PHP\_CodeSniffer unit tests still pass. The easiest way to contribute is to work on a checkout of the repository, or your own fork, rather than an installed PEAR version. If you do this, you can run the following commands to check if everything is ready to submit:
cd PHP_CodeSniffer
php scripts/phpcs
Which should give you no output, indicating that there are no coding standard errors. And then:
phpunit
Which should give you no failures or errors. You can ignore any skipped tests as these are for external tools.

View File

@@ -0,0 +1,9 @@
<?php
$phpCodeSnifferConfig = array (
'default_standard' => 'PSR2',
'report_format' => 'summary',
'show_warnings' => '0',
'show_progress' => '1',
'report_width' => '120',
)
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
<?php
/**
* The base class for all PHP_CodeSniffer documentation generators.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* The base class for all PHP_CodeSniffer documentation generators.
*
* Documentation generators are used to print documentation about code sniffs
* in a standard.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
abstract class PHP_CodeSniffer_DocGenerators_Generator
{
/**
* The name of the coding standard we are generating docs for.
*
* @var string
*/
private $_standard = '';
/**
* An array of sniffs that we are limiting the generated docs to.
*
* If this array is empty, docs are generated for all sniffs in the
* supplied coding standard.
*
* @var string
*/
private $_sniffs = array();
/**
* Constructs a PHP_CodeSniffer_DocGenerators_Generator object.
*
* @param string $standard The name of the coding standard to generate
* docs for.
* @param array $sniffs An array of sniffs that we are limiting the
* generated docs to.
*
* @see generate()
*/
public function __construct($standard, array $sniffs=array())
{
$this->_standard = $standard;
$this->_sniffs = $sniffs;
}//end __construct()
/**
* Retrieves the title of the sniff from the DOMNode supplied.
*
* @param DOMNode $doc The DOMNode object for the sniff.
* It represents the "documentation" tag in the XML
* standard file.
*
* @return string
*/
protected function getTitle(DOMNode $doc)
{
return $doc->getAttribute('title');
}//end getTitle()
/**
* Retrieves the name of the standard we are generating docs for.
*
* @return string
*/
protected function getStandard()
{
return $this->_standard;
}//end getStandard()
/**
* Generates the documentation for a standard.
*
* It's probably wise for doc generators to override this method so they
* have control over how the docs are produced. Otherwise, the processSniff
* method should be overridden to output content for each sniff.
*
* @return void
* @see processSniff()
*/
public function generate()
{
$standardFiles = $this->getStandardFiles();
foreach ($standardFiles as $standard) {
$doc = new DOMDocument();
$doc->load($standard);
$documentation = $doc->getElementsByTagName('documentation')->item(0);
$this->processSniff($documentation);
}
}//end generate()
/**
* Returns a list of paths to XML standard files for all sniffs in a standard.
*
* Any sniffs that do not have an XML standard file are obviously not included
* in the returned array. If documentation is only being generated for some
* sniffs (ie. $this->_sniffs is not empty) then all others sniffs will
* be filtered from the results as well.
*
* @return string[]
*/
protected function getStandardFiles()
{
$phpcs = new PHP_CodeSniffer();
$phpcs->process(array(), $this->_standard);
$sniffs = $phpcs->getSniffs();
$standardFiles = array();
foreach ($sniffs as $className => $sniffClass) {
$object = new ReflectionObject($sniffClass);
$sniff = $object->getFilename();
if (empty($this->_sniffs) === false) {
// We are limiting the docs to certain sniffs only, so filter
// out any unwanted sniffs.
$parts = explode('_', $className);
$sniffName = $parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5);
if (in_array($sniffName, $this->_sniffs) === false) {
continue;
}
}
$standardFile = str_replace(
DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR,
DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR,
$sniff
);
$standardFile = str_replace('Sniff.php', 'Standard.xml', $standardFile);
if (is_file($standardFile) === true) {
$standardFiles[] = $standardFile;
}
}//end foreach
return $standardFiles;
}//end getStandardFiles()
/**
* Process the documentation for a single sniff.
*
* Doc generators must implement this function to produce output.
*
* @param DOMNode $doc The DOMNode object for the sniff.
* It represents the "documentation" tag in the XML
* standard file.
*
* @return void
* @see generate()
*/
protected abstract function processSniff(DOMNode $doc);
}//end class

View File

@@ -0,0 +1,292 @@
<?php
/**
* A doc generator that outputs documentation in one big HTML file.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) {
throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found');
}
/**
* A doc generator that outputs documentation in one big HTML file.
*
* Output is in one large HTML file and is designed for you to style with
* your own stylesheet. It contains a table of contents at the top with anchors
* to each sniff.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_DocGenerators_HTML extends PHP_CodeSniffer_DocGenerators_Generator
{
/**
* Generates the documentation for a standard.
*
* @return void
* @see processSniff()
*/
public function generate()
{
ob_start();
$this->printHeader();
$standardFiles = $this->getStandardFiles();
$this->printToc($standardFiles);
foreach ($standardFiles as $standard) {
$doc = new DOMDocument();
$doc->load($standard);
$documentation = $doc->getElementsByTagName('documentation')->item(0);
$this->processSniff($documentation);
}
$this->printFooter();
$content = ob_get_contents();
ob_end_clean();
echo $content;
}//end generate()
/**
* Print the header of the HTML page.
*
* @return void
*/
protected function printHeader()
{
$standard = $this->getStandard();
echo '<html>'.PHP_EOL;
echo ' <head>'.PHP_EOL;
echo " <title>$standard Coding Standards</title>".PHP_EOL;
echo ' <style>
body {
background-color: #FFFFFF;
font-size: 14px;
font-family: Arial, Helvetica, sans-serif;
color: #000000;
}
h1 {
color: #666666;
font-size: 20px;
font-weight: bold;
margin-top: 0px;
background-color: #E6E7E8;
padding: 20px;
border: 1px solid #BBBBBB;
}
h2 {
color: #00A5E3;
font-size: 16px;
font-weight: normal;
margin-top: 50px;
}
.code-comparison {
width: 100%;
}
.code-comparison td {
border: 1px solid #CCCCCC;
}
.code-comparison-title, .code-comparison-code {
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
color: #000000;
vertical-align: top;
padding: 4px;
width: 50%;
background-color: #F1F1F1;
line-height: 15px;
}
.code-comparison-code {
font-family: Courier;
background-color: #F9F9F9;
}
.code-comparison-highlight {
background-color: #DDF1F7;
border: 1px solid #00A5E3;
line-height: 15px;
}
.tag-line {
text-align: center;
width: 100%;
margin-top: 30px;
font-size: 12px;
}
.tag-line a {
color: #000000;
}
</style>'.PHP_EOL;
echo ' </head>'.PHP_EOL;
echo ' <body>'.PHP_EOL;
echo " <h1>$standard Coding Standards</h1>".PHP_EOL;
}//end printHeader()
/**
* Print the table of contents for the standard.
*
* The TOC is just an unordered list of bookmarks to sniffs on the page.
*
* @param array $standardFiles An array of paths to the XML standard files.
*
* @return void
*/
protected function printToc($standardFiles)
{
echo ' <h2>Table of Contents</h2>'.PHP_EOL;
echo ' <ul class="toc">'.PHP_EOL;
foreach ($standardFiles as $standard) {
$doc = new DOMDocument();
$doc->load($standard);
$documentation = $doc->getElementsByTagName('documentation')->item(0);
$title = $this->getTitle($documentation);
echo ' <li><a href="#'.str_replace(' ', '-', $title)."\">$title</a></li>".PHP_EOL;
}
echo ' </ul>'.PHP_EOL;
}//end printToc()
/**
* Print the footer of the HTML page.
*
* @return void
*/
protected function printFooter()
{
// Turn off errors so we don't get timezone warnings if people
// don't have their timezone set.
$errorLevel = error_reporting(0);
echo ' <div class="tag-line">';
echo 'Documentation generated on '.date('r');
echo ' by <a href="https://github.com/squizlabs/PHP_CodeSniffer">PHP_CodeSniffer '.PHP_CodeSniffer::VERSION.'</a>';
echo '</div>'.PHP_EOL;
error_reporting($errorLevel);
echo ' </body>'.PHP_EOL;
echo '</html>'.PHP_EOL;
}//end printFooter()
/**
* Process the documentation for a single sniff.
*
* @param DOMNode $doc The DOMNode object for the sniff.
* It represents the "documentation" tag in the XML
* standard file.
*
* @return void
*/
public function processSniff(DOMNode $doc)
{
$title = $this->getTitle($doc);
echo ' <a name="'.str_replace(' ', '-', $title).'" />'.PHP_EOL;
echo " <h2>$title</h2>".PHP_EOL;
foreach ($doc->childNodes as $node) {
if ($node->nodeName === 'standard') {
$this->printTextBlock($node);
} else if ($node->nodeName === 'code_comparison') {
$this->printCodeComparisonBlock($node);
}
}
}//end processSniff()
/**
* Print a text block found in a standard.
*
* @param DOMNode $node The DOMNode object for the text block.
*
* @return void
*/
protected function printTextBlock($node)
{
$content = trim($node->nodeValue);
$content = htmlspecialchars($content);
// Allow em tags only.
$content = str_replace('&lt;em&gt;', '<em>', $content);
$content = str_replace('&lt;/em&gt;', '</em>', $content);
echo " <p class=\"text\">$content</p>".PHP_EOL;
}//end printTextBlock()
/**
* Print a code comparison block found in a standard.
*
* @param DOMNode $node The DOMNode object for the code comparison block.
*
* @return void
*/
protected function printCodeComparisonBlock($node)
{
$codeBlocks = $node->getElementsByTagName('code');
$firstTitle = $codeBlocks->item(0)->getAttribute('title');
$first = trim($codeBlocks->item(0)->nodeValue);
$first = str_replace('<?php', '&lt;?php', $first);
$first = str_replace("\n", '</br>', $first);
$first = str_replace(' ', '&nbsp;', $first);
$first = str_replace('<em>', '<span class="code-comparison-highlight">', $first);
$first = str_replace('</em>', '</span>', $first);
$secondTitle = $codeBlocks->item(1)->getAttribute('title');
$second = trim($codeBlocks->item(1)->nodeValue);
$second = str_replace('<?php', '&lt;?php', $second);
$second = str_replace("\n", '</br>', $second);
$second = str_replace(' ', '&nbsp;', $second);
$second = str_replace('<em>', '<span class="code-comparison-highlight">', $second);
$second = str_replace('</em>', '</span>', $second);
echo ' <table class="code-comparison">'.PHP_EOL;
echo ' <tr>'.PHP_EOL;
echo " <td class=\"code-comparison-title\">$firstTitle</td>".PHP_EOL;
echo " <td class=\"code-comparison-title\">$secondTitle</td>".PHP_EOL;
echo ' </tr>'.PHP_EOL;
echo ' <tr>'.PHP_EOL;
echo " <td class=\"code-comparison-code\">$first</td>".PHP_EOL;
echo " <td class=\"code-comparison-code\">$second</td>".PHP_EOL;
echo ' </tr>'.PHP_EOL;
echo ' </table>'.PHP_EOL;
}//end printCodeComparisonBlock()
}//end class

View File

@@ -0,0 +1,179 @@
<?php
/**
* A doc generator that outputs documentation in Markdown format.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Stefano Kowalke <blueduck@gmx.net>
* @copyright 2014 Arroba IT
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) {
throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found');
}
/**
* A doc generator that outputs documentation in Markdown format.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Stefano Kowalke <blueduck@gmx.net>
* @copyright 2014 Arroba IT
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_DocGenerators_Markdown extends PHP_CodeSniffer_DocGenerators_Generator
{
/**
* Generates the documentation for a standard.
*
* @return void
* @see processSniff()
*/
public function generate()
{
ob_start();
$this->printHeader();
$standardFiles = $this->getStandardFiles();
foreach ($standardFiles as $standard) {
$doc = new DOMDocument();
$doc->load($standard);
$documentation = $doc->getElementsByTagName('documentation')->item(0);
$this->processSniff($documentation);
}
$this->printFooter();
$content = ob_get_contents();
ob_end_clean();
echo $content;
}//end generate()
/**
* Print the markdown header.
*
* @return void
*/
protected function printHeader()
{
$standard = $this->getStandard();
echo "# $standard Coding Standard".PHP_EOL;
}//end printHeader()
/**
* Print the markdown footer.
*
* @return void
*/
protected function printFooter()
{
// Turn off errors so we don't get timezone warnings if people
// don't have their timezone set.
error_reporting(0);
echo 'Documentation generated on '.date('r');
echo ' by [PHP_CodeSniffer '.PHP_CodeSniffer::VERSION.'](https://github.com/squizlabs/PHP_CodeSniffer)';
}//end printFooter()
/**
* Process the documentation for a single sniff.
*
* @param DOMNode $doc The DOMNode object for the sniff.
* It represents the "documentation" tag in the XML
* standard file.
*
* @return void
*/
protected function processSniff(DOMNode $doc)
{
$title = $this->getTitle($doc);
echo "## $title".PHP_EOL;
foreach ($doc->childNodes as $node) {
if ($node->nodeName === 'standard') {
$this->printTextBlock($node);
} else if ($node->nodeName === 'code_comparison') {
$this->printCodeComparisonBlock($node);
}
}
}//end processSniff()
/**
* Print a text block found in a standard.
*
* @param DOMNode $node The DOMNode object for the text block.
*
* @return void
*/
protected function printTextBlock(DOMNode $node)
{
$content = trim($node->nodeValue);
$content = htmlspecialchars($content);
$content = str_replace('&lt;em&gt;', '*', $content);
$content = str_replace('&lt;/em&gt;', '*', $content);
echo $content.PHP_EOL;
}//end printTextBlock()
/**
* Print a code comparison block found in a standard.
*
* @param DOMNode $node The DOMNode object for the code comparison block.
*
* @return void
*/
protected function printCodeComparisonBlock(DOMNode $node)
{
$codeBlocks = $node->getElementsByTagName('code');
$firstTitle = $codeBlocks->item(0)->getAttribute('title');
$first = trim($codeBlocks->item(0)->nodeValue);
$first = str_replace("\n", "\n ", $first);
$first = str_replace('<em>', '', $first);
$first = str_replace('</em>', '', $first);
$secondTitle = $codeBlocks->item(1)->getAttribute('title');
$second = trim($codeBlocks->item(1)->nodeValue);
$second = str_replace("\n", "\n ", $second);
$second = str_replace('<em>', '', $second);
$second = str_replace('</em>', '', $second);
echo ' <table>'.PHP_EOL;
echo ' <tr>'.PHP_EOL;
echo " <th>$firstTitle</th>".PHP_EOL;
echo " <th>$secondTitle</th>".PHP_EOL;
echo ' </tr>'.PHP_EOL;
echo ' <tr>'.PHP_EOL;
echo '<td>'.PHP_EOL.PHP_EOL;
echo " $first".PHP_EOL.PHP_EOL;
echo '</td>'.PHP_EOL;
echo '<td>'.PHP_EOL.PHP_EOL;
echo " $second".PHP_EOL.PHP_EOL;
echo '</td>'.PHP_EOL;
echo ' </tr>'.PHP_EOL;
echo ' </table>'.PHP_EOL;
}//end printCodeComparisonBlock()
}//end class

View File

@@ -0,0 +1,265 @@
<?php
/**
* A doc generator that outputs text-based documentation.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) {
throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found');
}
/**
* A doc generator that outputs text-based documentation.
*
* Output is designed to be displayed in a terminal and is wrapped to 100 characters.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_DocGenerators_Text extends PHP_CodeSniffer_DocGenerators_Generator
{
/**
* Process the documentation for a single sniff.
*
* @param DOMNode $doc The DOMNode object for the sniff.
* It represents the "documentation" tag in the XML
* standard file.
*
* @return void
*/
public function processSniff(DOMNode $doc)
{
$this->printTitle($doc);
foreach ($doc->childNodes as $node) {
if ($node->nodeName === 'standard') {
$this->printTextBlock($node);
} else if ($node->nodeName === 'code_comparison') {
$this->printCodeComparisonBlock($node);
}
}
}//end processSniff()
/**
* Prints the title area for a single sniff.
*
* @param DOMNode $doc The DOMNode object for the sniff.
* It represents the "documentation" tag in the XML
* standard file.
*
* @return void
*/
protected function printTitle(DOMNode $doc)
{
$title = $this->getTitle($doc);
$standard = $this->getStandard();
echo PHP_EOL;
echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4));
echo strtoupper(PHP_EOL."| $standard CODING STANDARD: $title |".PHP_EOL);
echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4));
echo PHP_EOL.PHP_EOL;
}//end printTitle()
/**
* Print a text block found in a standard.
*
* @param DOMNode $node The DOMNode object for the text block.
*
* @return void
*/
protected function printTextBlock($node)
{
$text = trim($node->nodeValue);
$text = str_replace('<em>', '*', $text);
$text = str_replace('</em>', '*', $text);
$lines = array();
$tempLine = '';
$words = explode(' ', $text);
foreach ($words as $word) {
if (strlen($tempLine.$word) >= 99) {
if (strlen($tempLine.$word) === 99) {
// Adding the extra space will push us to the edge
// so we are done.
$lines[] = $tempLine.$word;
$tempLine = '';
} else if (strlen($tempLine.$word) === 100) {
// We are already at the edge, so we are done.
$lines[] = $tempLine.$word;
$tempLine = '';
} else {
$lines[] = rtrim($tempLine);
$tempLine = $word.' ';
}
} else {
$tempLine .= $word.' ';
}
}//end foreach
if ($tempLine !== '') {
$lines[] = rtrim($tempLine);
}
echo implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL;
}//end printTextBlock()
/**
* Print a code comparison block found in a standard.
*
* @param DOMNode $node The DOMNode object for the code comparison block.
*
* @return void
*/
protected function printCodeComparisonBlock($node)
{
$codeBlocks = $node->getElementsByTagName('code');
$first = trim($codeBlocks->item(0)->nodeValue);
$firstTitle = $codeBlocks->item(0)->getAttribute('title');
$firstTitleLines = array();
$tempTitle = '';
$words = explode(' ', $firstTitle);
foreach ($words as $word) {
if (strlen($tempTitle.$word) >= 45) {
if (strlen($tempTitle.$word) === 45) {
// Adding the extra space will push us to the edge
// so we are done.
$firstTitleLines[] = $tempTitle.$word;
$tempTitle = '';
} else if (strlen($tempTitle.$word) === 46) {
// We are already at the edge, so we are done.
$firstTitleLines[] = $tempTitle.$word;
$tempTitle = '';
} else {
$firstTitleLines[] = $tempTitle;
$tempTitle = $word;
}
} else {
$tempTitle .= $word.' ';
}
}//end foreach
if ($tempTitle !== '') {
$firstTitleLines[] = $tempTitle;
}
$first = str_replace('<em>', '', $first);
$first = str_replace('</em>', '', $first);
$firstLines = explode("\n", $first);
$second = trim($codeBlocks->item(1)->nodeValue);
$secondTitle = $codeBlocks->item(1)->getAttribute('title');
$secondTitleLines = array();
$tempTitle = '';
$words = explode(' ', $secondTitle);
foreach ($words as $word) {
if (strlen($tempTitle.$word) >= 45) {
if (strlen($tempTitle.$word) === 45) {
// Adding the extra space will push us to the edge
// so we are done.
$secondTitleLines[] = $tempTitle.$word;
$tempTitle = '';
} else if (strlen($tempTitle.$word) === 46) {
// We are already at the edge, so we are done.
$secondTitleLines[] = $tempTitle.$word;
$tempTitle = '';
} else {
$secondTitleLines[] = $tempTitle;
$tempTitle = $word;
}
} else {
$tempTitle .= $word.' ';
}
}//end foreach
if ($tempTitle !== '') {
$secondTitleLines[] = $tempTitle;
}
$second = str_replace('<em>', '', $second);
$second = str_replace('</em>', '', $second);
$secondLines = explode("\n", $second);
$maxCodeLines = max(count($firstLines), count($secondLines));
$maxTitleLines = max(count($firstTitleLines), count($secondTitleLines));
echo str_repeat('-', 41);
echo ' CODE COMPARISON ';
echo str_repeat('-', 42).PHP_EOL;
for ($i = 0; $i < $maxTitleLines; $i++) {
if (isset($firstTitleLines[$i]) === true) {
$firstLineText = $firstTitleLines[$i];
} else {
$firstLineText = '';
}
if (isset($secondTitleLines[$i]) === true) {
$secondLineText = $secondTitleLines[$i];
} else {
$secondLineText = '';
}
echo '| ';
echo $firstLineText.str_repeat(' ', (46 - strlen($firstLineText)));
echo ' | ';
echo $secondLineText.str_repeat(' ', (47 - strlen($secondLineText)));
echo ' |'.PHP_EOL;
}//end for
echo str_repeat('-', 100).PHP_EOL;
for ($i = 0; $i < $maxCodeLines; $i++) {
if (isset($firstLines[$i]) === true) {
$firstLineText = $firstLines[$i];
} else {
$firstLineText = '';
}
if (isset($secondLines[$i]) === true) {
$secondLineText = $secondLines[$i];
} else {
$secondLineText = '';
}
echo '| ';
echo $firstLineText.str_repeat(' ', (47 - strlen($firstLineText)));
echo '| ';
echo $secondLineText.str_repeat(' ', (48 - strlen($secondLineText)));
echo '|'.PHP_EOL;
}//end for
echo str_repeat('-', 100).PHP_EOL.PHP_EOL;
}//end printCodeComparisonBlock()
}//end class

View File

@@ -0,0 +1,31 @@
<?php
/**
* An exception thrown by PHP_CodeSniffer when it encounters an unrecoverable error.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* An exception thrown by PHP_CodeSniffer when it encounters an unrecoverable error.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Exception extends Exception
{
}//end class

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,741 @@
<?php
/**
* A helper class for fixing errors.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* A helper class for fixing errors.
*
* Provides helper functions that act upon a token array and modify the file
* content.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Fixer
{
/**
* Is the fixer enabled and fixing a file?
*
* Sniffs should check this value to ensure they are not
* doing extra processing to prepare for a fix when fixing is
* not required.
*
* @var boolean
*/
public $enabled = false;
/**
* The number of times we have looped over a file.
*
* @var int
*/
public $loops = 0;
/**
* The file being fixed.
*
* @var PHP_CodeSniffer_File
*/
private $_currentFile = null;
/**
* The list of tokens that make up the file contents.
*
* This is a simplified list which just contains the token content and nothing
* else. This is the array that is updated as fixes are made, not the file's
* token array. Imploding this array will give you the file content back.
*
* @var array(int => string)
*/
private $_tokens = array();
/**
* A list of tokens that have already been fixed.
*
* We don't allow the same token to be fixed more than once each time
* through a file as this can easily cause conflicts between sniffs.
*
* @var array(int)
*/
private $_fixedTokens = array();
/**
* The last value of each fixed token.
*
* If a token is being "fixed" back to its last value, the fix is
* probably conflicting with another.
*
* @var array(int => string)
*/
private $_oldTokenValues = array();
/**
* A list of tokens that have been fixed during a changeset.
*
* All changes in changeset must be able to be applied, or else
* the entire changeset is rejected.
*
* @var array()
*/
private $_changeset = array();
/**
* Is there an open changeset.
*
* @var boolean
*/
private $_inChangeset = false;
/**
* Is the current fixing loop in conflict?
*
* @var boolean
*/
private $_inConflict = false;
/**
* The number of fixes that have been performed.
*
* @var int
*/
private $_numFixes = 0;
/**
* Starts fixing a new file.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being fixed.
*
* @return void
*/
public function startFile($phpcsFile)
{
$this->_currentFile = $phpcsFile;
$this->_numFixes = 0;
$this->_fixedTokens = array();
$tokens = $phpcsFile->getTokens();
$this->_tokens = array();
foreach ($tokens as $index => $token) {
if (isset($token['orig_content']) === true) {
$this->_tokens[$index] = $token['orig_content'];
} else {
$this->_tokens[$index] = $token['content'];
}
}
}//end startFile()
/**
* Attempt to fix the file by processing it until no fixes are made.
*
* @return boolean
*/
public function fixFile()
{
$fixable = $this->_currentFile->getFixableCount();
if ($fixable === 0) {
// Nothing to fix.
return false;
}
$stdin = false;
$cliValues = $this->_currentFile->phpcs->cli->getCommandLineValues();
if (empty($cliValues['files']) === true) {
$stdin = true;
}
$this->enabled = true;
$this->loops = 0;
while ($this->loops < 50) {
ob_start();
// Only needed once file content has changed.
$contents = $this->getContents();
if (PHP_CODESNIFFER_VERBOSITY > 2) {
@ob_end_clean();
echo '---START FILE CONTENT---'.PHP_EOL;
$lines = explode($this->_currentFile->eolChar, $contents);
$max = strlen(count($lines));
foreach ($lines as $lineNum => $line) {
$lineNum++;
echo str_pad($lineNum, $max, ' ', STR_PAD_LEFT).'|'.$line.PHP_EOL;
}
echo '--- END FILE CONTENT ---'.PHP_EOL;
ob_start();
}
$this->_inConflict = false;
$this->_currentFile->refreshTokenListeners();
$this->_currentFile->start($contents);
ob_end_clean();
$this->loops++;
if (PHP_CODESNIFFER_CBF === true && $stdin === false) {
echo "\r".str_repeat(' ', 80)."\r";
echo "\t=> Fixing file: $this->_numFixes/$fixable violations remaining [made $this->loops pass";
if ($this->loops > 1) {
echo 'es';
}
echo ']... ';
}
if ($this->_numFixes === 0 && $this->_inConflict === false) {
// Nothing left to do.
break;
} else if (PHP_CODESNIFFER_VERBOSITY > 1) {
echo "\t* fixed $this->_numFixes violations, starting loop ".($this->loops + 1).' *'.PHP_EOL;
}
}//end while
$this->enabled = false;
if ($this->_numFixes > 0) {
if (PHP_CODESNIFFER_VERBOSITY > 1) {
@ob_end_clean();
echo "\t*** Reached maximum number of loops with $this->_numFixes violations left unfixed ***".PHP_EOL;
ob_start();
}
return false;
}
return true;
}//end fixFile()
/**
* Generates a text diff of the original file and the new content.
*
* @param string $filePath Optional file path to diff the file against.
* If not specified, the original version of the
* file will be used.
* @param boolean $colors Print colored output or not.
*
* @return string
*/
public function generateDiff($filePath=null, $colors=true)
{
if ($filePath === null) {
$filePath = $this->_currentFile->getFilename();
}
$cwd = getcwd().DIRECTORY_SEPARATOR;
if (strpos($filePath, $cwd) === 0) {
$filename = substr($filePath, strlen($cwd));
} else {
$filename = $filePath;
}
$contents = $this->getContents();
if (function_exists('sys_get_temp_dir') === true) {
// This is needed for HHVM support, but only available from 5.2.1.
$tempName = tempnam(sys_get_temp_dir(), 'phpcs-fixer');
$fixedFile = fopen($tempName, 'w');
} else {
$fixedFile = tmpfile();
$data = stream_get_meta_data($fixedFile);
$tempName = $data['uri'];
}
fwrite($fixedFile, $contents);
// We must use something like shell_exec() because whitespace at the end
// of lines is critical to diff files.
$filename = escapeshellarg($filename);
$cmd = "diff -u -L$filename -LPHP_CodeSniffer $filename \"$tempName\"";
$diff = shell_exec($cmd);
fclose($fixedFile);
if (is_file($tempName) === true) {
unlink($tempName);
}
if ($colors === false) {
return $diff;
}
$diffLines = explode(PHP_EOL, $diff);
if (count($diffLines) === 1) {
// Seems to be required for cygwin.
$diffLines = explode("\n", $diff);
}
$diff = array();
foreach ($diffLines as $line) {
if (isset($line[0]) === true) {
switch ($line[0]) {
case '-':
$diff[] = "\033[31m$line\033[0m";
break;
case '+':
$diff[] = "\033[32m$line\033[0m";
break;
default:
$diff[] = $line;
}
}
}
$diff = implode(PHP_EOL, $diff);
return $diff;
}//end generateDiff()
/**
* Get a count of fixes that have been performed on the file.
*
* This value is reset every time a new file is started, or an existing
* file is restarted.
*
* @return int
*/
public function getFixCount()
{
return $this->_numFixes;
}//end getFixCount()
/**
* Get the current content of the file, as a string.
*
* @return string
*/
public function getContents()
{
$contents = implode($this->_tokens);
return $contents;
}//end getContents()
/**
* Get the current fixed content of a token.
*
* This function takes changesets into account so should be used
* instead of directly accessing the token array.
*
* @param int $stackPtr The position of the token in the token stack.
*
* @return string
*/
public function getTokenContent($stackPtr)
{
if ($this->_inChangeset === true
&& isset($this->_changeset[$stackPtr]) === true
) {
return $this->_changeset[$stackPtr];
} else {
return $this->_tokens[$stackPtr];
}
}//end getTokenContent()
/**
* Start recording actions for a changeset.
*
* @return void
*/
public function beginChangeset()
{
if ($this->_inConflict === true) {
return false;
}
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$bt = debug_backtrace();
$sniff = $bt[1]['class'];
$line = $bt[0]['line'];
@ob_end_clean();
echo "\t=> Changeset started by $sniff (line $line)".PHP_EOL;
ob_start();
}
$this->_changeset = array();
$this->_inChangeset = true;
}//end beginChangeset()
/**
* Stop recording actions for a changeset, and apply logged changes.
*
* @return boolean
*/
public function endChangeset()
{
if ($this->_inConflict === true) {
return false;
}
$this->_inChangeset = false;
$success = true;
$applied = array();
foreach ($this->_changeset as $stackPtr => $content) {
$success = $this->replaceToken($stackPtr, $content);
if ($success === false) {
break;
} else {
$applied[] = $stackPtr;
}
}
if ($success === false) {
// Rolling back all changes.
foreach ($applied as $stackPtr) {
$this->revertToken($stackPtr);
}
if (PHP_CODESNIFFER_VERBOSITY > 1) {
@ob_end_clean();
echo "\t=> Changeset failed to apply".PHP_EOL;
ob_start();
}
} else if (PHP_CODESNIFFER_VERBOSITY > 1) {
$fixes = count($this->_changeset);
@ob_end_clean();
echo "\t=> Changeset ended: $fixes changes applied".PHP_EOL;
ob_start();
}
$this->_changeset = array();
}//end endChangeset()
/**
* Stop recording actions for a changeset, and discard logged changes.
*
* @return void
*/
public function rollbackChangeset()
{
$this->_inChangeset = false;
$this->_inConflict = false;
if (empty($this->_changeset) === false) {
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$bt = debug_backtrace();
if ($bt[1]['class'] === 'PHP_CodeSniffer_Fixer') {
$sniff = $bt[2]['class'];
$line = $bt[1]['line'];
} else {
$sniff = $bt[1]['class'];
$line = $bt[0]['line'];
}
$numChanges = count($this->_changeset);
@ob_end_clean();
echo "\t\tR: $sniff (line $line) rolled back the changeset ($numChanges changes)".PHP_EOL;
echo "\t=> Changeset rolled back".PHP_EOL;
ob_start();
}
$this->_changeset = array();
}//end if
}//end rollbackChangeset()
/**
* Replace the entire contents of a token.
*
* @param int $stackPtr The position of the token in the token stack.
* @param string $content The new content of the token.
*
* @return bool If the change was accepted.
*/
public function replaceToken($stackPtr, $content)
{
if ($this->_inConflict === true) {
return false;
}
if ($this->_inChangeset === false
&& isset($this->_fixedTokens[$stackPtr]) === true
) {
$indent = "\t";
if (empty($this->_changeset) === false) {
$indent .= "\t";
}
if (PHP_CODESNIFFER_VERBOSITY > 1) {
@ob_end_clean();
echo "$indent* token $stackPtr has already been modified, skipping *".PHP_EOL;
ob_start();
}
return false;
}
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$bt = debug_backtrace();
if ($bt[1]['class'] === 'PHP_CodeSniffer_Fixer') {
$sniff = $bt[2]['class'];
$line = $bt[1]['line'];
} else {
$sniff = $bt[1]['class'];
$line = $bt[0]['line'];
}
$tokens = $this->_currentFile->getTokens();
$type = $tokens[$stackPtr]['type'];
$oldContent = PHP_CodeSniffer::prepareForOutput($this->_tokens[$stackPtr]);
$newContent = PHP_CodeSniffer::prepareForOutput($content);
if (trim($this->_tokens[$stackPtr]) === '' && isset($this->_tokens[($stackPtr + 1)]) === true) {
// Add some context for whitespace only changes.
$append = PHP_CodeSniffer::prepareForOutput($this->_tokens[($stackPtr + 1)]);
$oldContent .= $append;
$newContent .= $append;
}
}//end if
if ($this->_inChangeset === true) {
$this->_changeset[$stackPtr] = $content;
if (PHP_CODESNIFFER_VERBOSITY > 1) {
@ob_end_clean();
echo "\t\tQ: $sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
ob_start();
}
return true;
}
if (isset($this->_oldTokenValues[$stackPtr]) === false) {
$this->_oldTokenValues[$stackPtr] = array(
'curr' => $content,
'prev' => $this->_tokens[$stackPtr],
'loop' => $this->loops,
);
} else {
if ($this->_oldTokenValues[$stackPtr]['prev'] === $content
&& $this->_oldTokenValues[$stackPtr]['loop'] === ($this->loops - 1)
) {
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$indent = "\t";
if (empty($this->_changeset) === false) {
$indent .= "\t";
}
$loop = $this->_oldTokenValues[$stackPtr]['loop'];
@ob_end_clean();
echo "$indent**** $sniff (line $line) has possible conflict with another sniff on loop $loop; caused by the following change ****".PHP_EOL;
echo "$indent**** replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\" ****".PHP_EOL;
}
if ($this->_oldTokenValues[$stackPtr]['loop'] >= ($this->loops - 1)) {
$this->_inConflict = true;
if (PHP_CODESNIFFER_VERBOSITY > 1) {
echo "$indent**** ignoring all changes until next loop ****".PHP_EOL;
}
}
if (PHP_CODESNIFFER_VERBOSITY > 1) {
ob_start();
}
return false;
}//end if
$this->_oldTokenValues[$stackPtr]['prev'] = $this->_oldTokenValues[$stackPtr]['curr'];
$this->_oldTokenValues[$stackPtr]['curr'] = $content;
$this->_oldTokenValues[$stackPtr]['loop'] = $this->loops;
}//end if
$this->_fixedTokens[$stackPtr] = $this->_tokens[$stackPtr];
$this->_tokens[$stackPtr] = $content;
$this->_numFixes++;
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$indent = "\t";
if (empty($this->_changeset) === false) {
$indent .= "\tA: ";
}
@ob_end_clean();
echo "$indent$sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
ob_start();
}
return true;
}//end replaceToken()
/**
* Reverts the previous fix made to a token.
*
* @param int $stackPtr The position of the token in the token stack.
*
* @return bool If a change was reverted.
*/
public function revertToken($stackPtr)
{
if (isset($this->_fixedTokens[$stackPtr]) === false) {
return false;
}
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$bt = debug_backtrace();
if ($bt[1]['class'] === 'PHP_CodeSniffer_Fixer') {
$sniff = $bt[2]['class'];
$line = $bt[1]['line'];
} else {
$sniff = $bt[1]['class'];
$line = $bt[0]['line'];
}
$tokens = $this->_currentFile->getTokens();
$type = $tokens[$stackPtr]['type'];
$oldContent = PHP_CodeSniffer::prepareForOutput($this->_tokens[$stackPtr]);
$newContent = PHP_CodeSniffer::prepareForOutput($this->_fixedTokens[$stackPtr]);
if (trim($this->_tokens[$stackPtr]) === '' && isset($tokens[($stackPtr + 1)]) === true) {
// Add some context for whitespace only changes.
$append = PHP_CodeSniffer::prepareForOutput($this->_tokens[($stackPtr + 1)]);
$oldContent .= $append;
$newContent .= $append;
}
}//end if
$this->_tokens[$stackPtr] = $this->_fixedTokens[$stackPtr];
unset($this->_fixedTokens[$stackPtr]);
$this->_numFixes--;
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$indent = "\t";
if (empty($this->_changeset) === false) {
$indent .= "\tR: ";
}
@ob_end_clean();
echo "$indent$sniff (line $line) reverted token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
ob_start();
}
return true;
}//end revertToken()
/**
* Replace the content of a token with a part of its current content.
*
* @param int $stackPtr The position of the token in the token stack.
* @param int $start The first character to keep.
* @param int $length The number of chacters to keep. If NULL, the content of
* the token from $start to the end of the content is kept.
*
* @return bool If the change was accepted.
*/
public function substrToken($stackPtr, $start, $length=null)
{
$current = $this->getTokenContent($stackPtr);
if ($length === null) {
$newContent = substr($current, $start);
} else {
$newContent = substr($current, $start, $length);
}
return $this->replaceToken($stackPtr, $newContent);
}//end substrToken()
/**
* Adds a newline to end of a token's content.
*
* @param int $stackPtr The position of the token in the token stack.
*
* @return bool If the change was accepted.
*/
public function addNewline($stackPtr)
{
$current = $this->getTokenContent($stackPtr);
return $this->replaceToken($stackPtr, $current.$this->_currentFile->eolChar);
}//end addNewline()
/**
* Adds a newline to the start of a token's content.
*
* @param int $stackPtr The position of the token in the token stack.
*
* @return bool If the change was accepted.
*/
public function addNewlineBefore($stackPtr)
{
$current = $this->getTokenContent($stackPtr);
return $this->replaceToken($stackPtr, $this->_currentFile->eolChar.$current);
}//end addNewlineBefore()
/**
* Adds content to the end of a token's current content.
*
* @param int $stackPtr The position of the token in the token stack.
* @param string $content The content to add.
*
* @return bool If the change was accepted.
*/
public function addContent($stackPtr, $content)
{
$current = $this->getTokenContent($stackPtr);
return $this->replaceToken($stackPtr, $current.$content);
}//end addContent()
/**
* Adds content to the start of a token's current content.
*
* @param int $stackPtr The position of the token in the token stack.
* @param string $content The content to add.
*
* @return bool If the change was accepted.
*/
public function addContentBefore($stackPtr, $content)
{
$current = $this->getTokenContent($stackPtr);
return $this->replaceToken($stackPtr, $content.$current);
}//end addContentBefore()
}//end class

View File

@@ -0,0 +1,83 @@
<?php
/**
* Represents a PHP_CodeSniffer report.
*
* PHP version 5.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Represents a PHP_CodeSniffer report.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
interface PHP_CodeSniffer_Report
{
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
);
/**
* Generate the actual report.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
);
}//end interface

View File

@@ -0,0 +1,425 @@
<?php
/**
* A class to manage reporting.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* A class to manage reporting.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reporting
{
/**
* Total number of files that contain errors or warnings.
*
* @var int
*/
public $totalFiles = 0;
/**
* Total number of errors found during the run.
*
* @var int
*/
public $totalErrors = 0;
/**
* Total number of warnings found during the run.
*
* @var int
*/
public $totalWarnings = 0;
/**
* Total number of errors/warnings that can be fixed.
*
* @var int
*/
public $totalFixable = 0;
/**
* When the PHPCS run started.
*
* @var float
*/
public static $startTime = 0;
/**
* A list of reports that have written partial report output.
*
* @var array
*/
private $_cachedReports = array();
/**
* A cache of report objects.
*
* @var array
*/
private $_reports = array();
/**
* A cache of opened tmp files.
*
* @var array
*/
private $_tmpFiles = array();
/**
* Produce the appropriate report object based on $type parameter.
*
* @param string $type The type of the report.
*
* @return PHP_CodeSniffer_Report
* @throws PHP_CodeSniffer_Exception If report is not available.
*/
public function factory($type)
{
$type = ucfirst($type);
if (isset($this->_reports[$type]) === true) {
return $this->_reports[$type];
}
if (strpos($type, '.') !== false) {
// This is a path to a custom report class.
$filename = realpath($type);
if ($filename === false) {
echo 'ERROR: Custom report "'.$type.'" not found'.PHP_EOL;
exit(2);
}
$reportClassName = 'PHP_CodeSniffer_Reports_'.basename($filename);
$reportClassName = substr($reportClassName, 0, strpos($reportClassName, '.'));
include_once $filename;
} else {
$filename = $type.'.php';
$reportClassName = 'PHP_CodeSniffer_Reports_'.$type;
if (class_exists($reportClassName, true) === false) {
echo 'ERROR: Report type "'.$type.'" not found'.PHP_EOL;
exit(2);
}
}//end if
$reportClass = new $reportClassName();
if (false === ($reportClass instanceof PHP_CodeSniffer_Report)) {
throw new PHP_CodeSniffer_Exception('Class "'.$reportClassName.'" must implement the "PHP_CodeSniffer_Report" interface.');
}
$this->_reports[$type] = $reportClass;
return $this->_reports[$type];
}//end factory()
/**
* Actually generates the report.
*
* @param PHP_CodeSniffer_File $phpcsFile The file that has been processed.
* @param array $cliValues An array of command line arguments.
*
* @return void
*/
public function cacheFileReport(PHP_CodeSniffer_File $phpcsFile, array $cliValues)
{
if (isset($cliValues['reports']) === false) {
// This happens during unit testing, or any time someone just wants
// the error data and not the printed report.
return;
}
$reportData = $this->prepareFileReport($phpcsFile);
$errorsShown = false;
foreach ($cliValues['reports'] as $report => $output) {
$reportClass = $this->factory($report);
$report = get_class($reportClass);
ob_start();
$result = $reportClass->generateFileReport($reportData, $phpcsFile, $cliValues['showSources'], $cliValues['reportWidth']);
if ($result === true) {
$errorsShown = true;
}
$generatedReport = ob_get_contents();
ob_end_clean();
if ($output === null && $cliValues['reportFile'] !== null) {
$output = $cliValues['reportFile'];
}
if ($output === null) {
// Using a temp file.
if (isset($this->_tmpFiles[$report]) === false) {
if (function_exists('sys_get_temp_dir') === true) {
// This is needed for HHVM support, but only available from 5.2.1.
$this->_tmpFiles[$report] = fopen(tempnam(sys_get_temp_dir(), 'phpcs'), 'w');
} else {
$this->_tmpFiles[$report] = tmpfile();
}
}
fwrite($this->_tmpFiles[$report], $generatedReport);
} else {
$flags = FILE_APPEND;
if (isset($this->_cachedReports[$report]) === false) {
$this->_cachedReports[$report] = true;
$flags = null;
}
file_put_contents($output, $generatedReport, $flags);
}//end if
}//end foreach
if ($errorsShown === true) {
$this->totalFiles++;
$this->totalErrors += $reportData['errors'];
$this->totalWarnings += $reportData['warnings'];
$this->totalFixable += $reportData['fixable'];
}
}//end cacheFileReport()
/**
* Generates and prints a final report.
*
* Returns an array with the number of errors and the number of
* warnings, in the form ['errors' => int, 'warnings' => int].
*
* @param string $report Report type.
* @param boolean $showSources Show sources?
* @param array $cliValues An array of command line arguments.
* @param string $reportFile Report file to generate.
* @param integer $reportWidth Report max width.
*
* @return int[]
*/
public function printReport(
$report,
$showSources,
array $cliValues,
$reportFile='',
$reportWidth=80
) {
$reportClass = $this->factory($report);
$report = get_class($reportClass);
if ($reportFile !== null) {
$filename = $reportFile;
$toScreen = false;
if (file_exists($filename) === true
&& isset($this->_cachedReports[$report]) === true
) {
$reportCache = file_get_contents($filename);
} else {
$reportCache = '';
}
} else {
if (isset($this->_tmpFiles[$report]) === true) {
$data = stream_get_meta_data($this->_tmpFiles[$report]);
$filename = $data['uri'];
$reportCache = file_get_contents($filename);
fclose($this->_tmpFiles[$report]);
} else {
$reportCache = '';
$filename = null;
}
$toScreen = true;
}//end if
ob_start();
$reportClass->generate(
$reportCache,
$this->totalFiles,
$this->totalErrors,
$this->totalWarnings,
$this->totalFixable,
$showSources,
$reportWidth,
$toScreen
);
$generatedReport = ob_get_contents();
ob_end_clean();
if ($cliValues['colors'] !== true || $reportFile !== null) {
$generatedReport = preg_replace('`\033\[[0-9]+m`', '', $generatedReport);
}
if ($reportFile !== null) {
if (PHP_CODESNIFFER_VERBOSITY > 0) {
echo $generatedReport;
}
file_put_contents($reportFile, $generatedReport.PHP_EOL);
} else {
echo $generatedReport;
if ($filename !== null && file_exists($filename) === true) {
unlink($filename);
}
}
return array(
'errors' => $this->totalErrors,
'warnings' => $this->totalWarnings,
);
}//end printReport()
/**
* Pre-process and package violations for all files.
*
* Used by error reports to get a packaged list of all errors in each file.
*
* @param PHP_CodeSniffer_File $phpcsFile The file that has been processed.
*
* @return array
*/
public function prepareFileReport(PHP_CodeSniffer_File $phpcsFile)
{
$report = array(
'filename' => $phpcsFile->getFilename(),
'errors' => $phpcsFile->getErrorCount(),
'warnings' => $phpcsFile->getWarningCount(),
'fixable' => $phpcsFile->getFixableCount(),
'messages' => array(),
);
if ($report['errors'] === 0 && $report['warnings'] === 0) {
// Prefect score!
return $report;
}
$errors = array();
// Merge errors and warnings.
foreach ($phpcsFile->getErrors() as $line => $lineErrors) {
if (is_array($lineErrors) === false) {
continue;
}
foreach ($lineErrors as $column => $colErrors) {
$newErrors = array();
foreach ($colErrors as $data) {
$newErrors[] = array(
'message' => $data['message'],
'source' => $data['source'],
'severity' => $data['severity'],
'fixable' => $data['fixable'],
'type' => 'ERROR',
);
}//end foreach
$errors[$line][$column] = $newErrors;
}//end foreach
ksort($errors[$line]);
}//end foreach
foreach ($phpcsFile->getWarnings() as $line => $lineWarnings) {
if (is_array($lineWarnings) === false) {
continue;
}
foreach ($lineWarnings as $column => $colWarnings) {
$newWarnings = array();
foreach ($colWarnings as $data) {
$newWarnings[] = array(
'message' => $data['message'],
'source' => $data['source'],
'severity' => $data['severity'],
'fixable' => $data['fixable'],
'type' => 'WARNING',
);
}//end foreach
if (isset($errors[$line]) === false) {
$errors[$line] = array();
}
if (isset($errors[$line][$column]) === true) {
$errors[$line][$column] = array_merge(
$newWarnings,
$errors[$line][$column]
);
} else {
$errors[$line][$column] = $newWarnings;
}
}//end foreach
ksort($errors[$line]);
}//end foreach
ksort($errors);
$report['messages'] = $errors;
return $report;
}//end prepareFileReport()
/**
* Start recording time for the run.
*
* @return void
*/
public static function startTiming()
{
self::$startTime = microtime(true);
}//end startTiming()
/**
* Print information about the run.
*
* @return void
*/
public static function printRunTime()
{
$time = ((microtime(true) - self::$startTime) * 1000);
if ($time > 60000) {
$mins = floor($time / 60000);
$secs = round((($time % 60000) / 1000), 2);
$time = $mins.' mins';
if ($secs !== 0) {
$time .= ", $secs secs";
}
} else if ($time > 1000) {
$time = round(($time / 1000), 2).' secs';
} else {
$time = round($time).'ms';
}
$mem = round((memory_get_peak_usage(true) / (1024 * 1024)), 2).'Mb';
echo "Time: $time; Memory: $mem".PHP_EOL.PHP_EOL;
}//end printRunTime()
}//end class

View File

@@ -0,0 +1,151 @@
<?php
/**
* CBF report for PHP_CodeSniffer.
*
* This report implements the various auto-fixing features of the
* PHPCBF script and is not intended (or allowed) to be selected as a
* report from the command line.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* CBF report for PHP_CodeSniffer.
*
* This report implements the various auto-fixing features of the
* PHPCBF script and is not intended (or allowed) to be selected as a
* report from the command line.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Cbf implements PHP_CodeSniffer_Report
{
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
$cliValues = $phpcsFile->phpcs->cli->getCommandLineValues();
$errors = $phpcsFile->getFixableCount();
if ($errors !== 0) {
if (empty($cliValues['files']) === false) {
ob_end_clean();
$errors = $phpcsFile->getFixableCount();
$startTime = microtime(true);
echo "\t=> Fixing file: $errors/$errors violations remaining";
}
$fixed = $phpcsFile->fixer->fixFile();
}
if (empty($cliValues['files']) === true) {
// Replacing STDIN, so output current file to STDOUT
// even if nothing was fixed. Exit here because we
// can't process any more than 1 file in this setup.
echo $phpcsFile->fixer->getContents();
ob_end_flush();
exit(1);
}
if ($errors === 0) {
return false;
}
if ($fixed === false) {
echo 'ERROR';
} else {
echo 'DONE';
}
$timeTaken = ((microtime(true) - $startTime) * 1000);
if ($timeTaken < 1000) {
$timeTaken = round($timeTaken);
echo " in {$timeTaken}ms".PHP_EOL;
} else {
$timeTaken = round(($timeTaken / 1000), 2);
echo " in $timeTaken secs".PHP_EOL;
}
if ($fixed === true) {
$newFilename = $report['filename'].$cliValues['phpcbf-suffix'];
$newContent = $phpcsFile->fixer->getContents();
file_put_contents($newFilename, $newContent);
if ($newFilename === $report['filename']) {
echo "\t=> File was overwritten".PHP_EOL;
} else {
echo "\t=> Fixed file written to ".basename($newFilename).PHP_EOL;
}
}
ob_start();
return $fixed;
}//end generateFileReport()
/**
* Prints all errors and warnings for each file processed.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
echo $cachedData;
echo "Fixed $totalFiles files".PHP_EOL;
}//end generate()
}//end class

View File

@@ -0,0 +1,128 @@
<?php
/**
* Checkstyle report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Checkstyle report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Checkstyle implements PHP_CodeSniffer_Report
{
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
$out = new XMLWriter;
$out->openMemory();
$out->setIndent(true);
if ($report['errors'] === 0 && $report['warnings'] === 0) {
// Nothing to print.
return false;
}
$out->startElement('file');
$out->writeAttribute('name', $report['filename']);
foreach ($report['messages'] as $line => $lineErrors) {
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$error['type'] = strtolower($error['type']);
if (PHP_CODESNIFFER_ENCODING !== 'utf-8') {
$error['message'] = iconv(PHP_CODESNIFFER_ENCODING, 'utf-8', $error['message']);
}
$out->startElement('error');
$out->writeAttribute('line', $line);
$out->writeAttribute('column', $column);
$out->writeAttribute('severity', $error['type']);
$out->writeAttribute('message', $error['message']);
$out->writeAttribute('source', $error['source']);
$out->endElement();
}
}
}//end foreach
$out->endElement();
echo $out->flush();
return true;
}//end generateFileReport()
/**
* Prints all violations for processed files, in a Checkstyle format.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
echo '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
echo '<checkstyle version="'.PHP_CodeSniffer::VERSION.'">'.PHP_EOL;
echo $cachedData;
echo '</checkstyle>'.PHP_EOL;
}//end generate()
}//end class

View File

@@ -0,0 +1,111 @@
<?php
/**
* Csv report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Csv report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Csv implements PHP_CodeSniffer_Report
{
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
if ($report['errors'] === 0 && $report['warnings'] === 0) {
// Nothing to print.
return false;
}
foreach ($report['messages'] as $line => $lineErrors) {
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$filename = str_replace('"', '\"', $report['filename']);
$message = str_replace('"', '\"', $error['message']);
$type = strtolower($error['type']);
$source = $error['source'];
$severity = $error['severity'];
$fixable = (int) $error['fixable'];
echo "\"$filename\",$line,$column,$type,\"$message\",$source,$severity,$fixable".PHP_EOL;
}
}
}
return true;
}//end generateFileReport()
/**
* Generates a csv report.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
echo 'File,Line,Column,Type,Message,Source,Severity,Fixable'.PHP_EOL;
echo $cachedData;
}//end generate()
}//end class

View File

@@ -0,0 +1,149 @@
<?php
/**
* Diff report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Diff report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Diff implements PHP_CodeSniffer_Report
{
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
$errors = $phpcsFile->getFixableCount();
if ($errors === 0) {
return false;
}
if (PHP_CODESNIFFER_VERBOSITY > 1) {
ob_end_clean();
echo "\t*** START FILE FIXING ***".PHP_EOL;
}
if (PHP_CODESNIFFER_CBF === true) {
ob_end_clean();
$startTime = microtime(true);
echo "\t=> Fixing file: $errors/$errors violations remaining";
}
$fixed = $phpcsFile->fixer->fixFile();
if (PHP_CODESNIFFER_CBF === true) {
if ($fixed === false) {
echo "\033[31mERROR\033[0m";
} else {
echo "\033[32mDONE\033[0m";
}
$timeTaken = ((microtime(true) - $startTime) * 1000);
if ($timeTaken < 1000) {
$timeTaken = round($timeTaken);
echo " in {$timeTaken}ms".PHP_EOL;
} else {
$timeTaken = round(($timeTaken / 1000), 2);
echo " in $timeTaken secs".PHP_EOL;
}
ob_start();
}
if (PHP_CODESNIFFER_VERBOSITY > 1) {
echo "\t*** END FILE FIXING ***".PHP_EOL;
ob_start();
}
if ($fixed === false) {
return false;
}
if (PHP_CODESNIFFER_CBF === true) {
// Diff without colours.
$diff = $phpcsFile->fixer->generateDiff(null, false);
} else {
$diff = $phpcsFile->fixer->generateDiff();
}
if ($diff === '') {
// Nothing to print.
return false;
}
echo $diff.PHP_EOL;
return true;
}//end generateFileReport()
/**
* Prints all errors and warnings for each file processed.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
echo $cachedData;
if ($toScreen === true) {
echo PHP_EOL;
}
}//end generate()
}//end class

View File

@@ -0,0 +1,110 @@
<?php
/**
* Emacs report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Emacs report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Emacs implements PHP_CodeSniffer_Report
{
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
if ($report['errors'] === 0 && $report['warnings'] === 0) {
// Nothing to print.
return false;
}
foreach ($report['messages'] as $line => $lineErrors) {
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$message = $error['message'];
if ($showSources === true) {
$message .= ' ('.$error['source'].')';
}
$type = strtolower($error['type']);
echo $report['filename'].':'.$line.':'.$column.': '.$type.' - '.$message.PHP_EOL;
}
}
}
return true;
}//end generateFileReport()
/**
* Generates an emacs report.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
echo $cachedData;
}//end generate()
}//end class

View File

@@ -0,0 +1,237 @@
<?php
/**
* Full report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Full report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Full implements PHP_CodeSniffer_Report
{
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
if ($report['errors'] === 0 && $report['warnings'] === 0) {
// Nothing to print.
return false;
}
// The length of the word ERROR or WARNING; used for padding.
if ($report['warnings'] > 0) {
$typeLength = 7;
} else {
$typeLength = 5;
}
// Work out the max line number length for formatting.
$maxLineNumLength = max(array_map('strlen', array_keys($report['messages'])));
// The padding that all lines will require that are
// printing an error message overflow.
$paddingLine2 = str_repeat(' ', ($maxLineNumLength + 1));
$paddingLine2 .= ' | ';
$paddingLine2 .= str_repeat(' ', $typeLength);
$paddingLine2 .= ' | ';
if ($report['fixable'] > 0) {
$paddingLine2 .= ' ';
}
$paddingLength = strlen($paddingLine2);
// Make sure the report width isn't too big.
$maxErrorLength = 0;
foreach ($report['messages'] as $line => $lineErrors) {
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$length = strlen($error['message']);
if ($showSources === true) {
$length += (strlen($error['source']) + 3);
}
$maxErrorLength = max($maxErrorLength, ($length + 1));
}
}
}
$file = $report['filename'];
$fileLength = strlen($file);
$maxWidth = max(($fileLength + 6), ($maxErrorLength + $paddingLength));
$width = min($width, $maxWidth);
if ($width < 70) {
$width = 70;
}
echo PHP_EOL."\033[1mFILE: ";
if ($fileLength <= ($width - 6)) {
echo $file;
} else {
echo '...'.substr($file, ($fileLength - ($width - 6)));
}
echo "\033[0m".PHP_EOL;
echo str_repeat('-', $width).PHP_EOL;
echo "\033[1m".'FOUND '.$report['errors'].' ERROR';
if ($report['errors'] !== 1) {
echo 'S';
}
if ($report['warnings'] > 0) {
echo ' AND '.$report['warnings'].' WARNING';
if ($report['warnings'] !== 1) {
echo 'S';
}
}
echo ' AFFECTING '.count($report['messages']).' LINE';
if (count($report['messages']) !== 1) {
echo 'S';
}
echo "\033[0m".PHP_EOL;
echo str_repeat('-', $width).PHP_EOL;
// The maximum amount of space an error message can use.
$maxErrorSpace = ($width - $paddingLength - 1);
if ($showSources === true) {
// Account for the chars used to print colors.
$maxErrorSpace += 8;
}
foreach ($report['messages'] as $line => $lineErrors) {
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$message = $error['message'];
$message = str_replace("\n", "\n".$paddingLine2, $message);
if ($showSources === true) {
$message = "\033[1m".$message."\033[0m".' ('.$error['source'].')';
}
// The padding that goes on the front of the line.
$padding = ($maxLineNumLength - strlen($line));
$errorMsg = wordwrap(
$message,
$maxErrorSpace,
PHP_EOL.$paddingLine2
);
echo ' '.str_repeat(' ', $padding).$line.' | ';
if ($error['type'] === 'ERROR') {
echo "\033[31mERROR\033[0m";
if ($report['warnings'] > 0) {
echo ' ';
}
} else {
echo "\033[33mWARNING\033[0m";
}
echo ' | ';
if ($report['fixable'] > 0) {
echo '[';
if ($error['fixable'] === true) {
echo 'x';
} else {
echo ' ';
}
echo '] ';
}
echo $errorMsg.PHP_EOL;
}//end foreach
}//end foreach
}//end foreach
echo str_repeat('-', $width).PHP_EOL;
if ($report['fixable'] > 0) {
echo "\033[1m".'PHPCBF CAN FIX THE '.$report['fixable'].' MARKED SNIFF VIOLATIONS AUTOMATICALLY'."\033[0m".PHP_EOL;
echo str_repeat('-', $width).PHP_EOL;
}
echo PHP_EOL;
return true;
}//end generateFileReport()
/**
* Prints all errors and warnings for each file processed.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
if ($cachedData === '') {
return;
}
echo $cachedData;
if ($toScreen === true && PHP_CODESNIFFER_INTERACTIVE === false) {
PHP_CodeSniffer_Reporting::printRunTime();
}
}//end generate()
}//end class

View File

@@ -0,0 +1,105 @@
<?php
/**
* Gitblame report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Ben Selby <benmatselby@gmail.com>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Gitblame report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Ben Selby <benmatselby@gmail.com>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: 1.2.2
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Gitblame extends PHP_CodeSniffer_Reports_VersionControl
{
/**
* The name of the report we want in the output
*
* @var string
*/
protected $reportName = 'GIT';
/**
* Extract the author from a blame line.
*
* @param string $line Line to parse.
*
* @return mixed string or false if impossible to recover.
*/
protected function getAuthor($line)
{
$blameParts = array();
$line = preg_replace('|\s+|', ' ', $line);
preg_match(
'|\(.+[0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]+\)|',
$line,
$blameParts
);
if (isset($blameParts[0]) === false) {
return false;
}
$parts = explode(' ', $blameParts[0]);
if (count($parts) < 2) {
return false;
}
$parts = array_slice($parts, 0, (count($parts) - 2));
$author = preg_replace('|\(|', '', implode($parts, ' '));
return $author;
}//end getAuthor()
/**
* Gets the blame output.
*
* @param string $filename File to blame.
*
* @return array
*/
protected function getBlameContent($filename)
{
$cwd = getcwd();
chdir(dirname($filename));
$command = 'git blame --date=short "'.$filename.'" 2>&1';
$handle = popen($command, 'r');
if ($handle === false) {
echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL;
exit(2);
}
$rawContent = stream_get_contents($handle);
fclose($handle);
$blames = explode("\n", $rawContent);
chdir($cwd);
return $blames;
}//end getBlameContent()
}//end class

View File

@@ -0,0 +1,124 @@
<?php
/**
* Mercurial report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Ben Selby <benmatselby@gmail.com>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Mercurial report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Ben Selby <benmatselby@gmail.com>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Hgblame extends PHP_CodeSniffer_Reports_VersionControl
{
/**
* The name of the report we want in the output
*
* @var string
*/
protected $reportName = 'MERCURIAL';
/**
* Extract the author from a blame line.
*
* @param string $line Line to parse.
*
* @return mixed string or false if impossible to recover.
*/
protected function getAuthor($line)
{
$blameParts = array();
$line = preg_replace('|\s+|', ' ', $line);
preg_match(
'|(.+[0-9]{2}:[0-9]{2}:[0-9]{2}\s[0-9]{4}\s.[0-9]{4}:)|',
$line,
$blameParts
);
if (isset($blameParts[0]) === false) {
return false;
}
$parts = explode(' ', $blameParts[0]);
if (count($parts) < 6) {
return false;
}
$parts = array_slice($parts, 0, (count($parts) - 6));
return trim(preg_replace('|<.+>|', '', implode($parts, ' ')));
}//end getAuthor()
/**
* Gets the blame output.
*
* @param string $filename File to blame.
*
* @return array
*/
protected function getBlameContent($filename)
{
$cwd = getcwd();
$fileParts = explode(DIRECTORY_SEPARATOR, $filename);
$found = false;
$location = '';
while (empty($fileParts) === false) {
array_pop($fileParts);
$location = implode($fileParts, DIRECTORY_SEPARATOR);
if (is_dir($location.DIRECTORY_SEPARATOR.'.hg') === true) {
$found = true;
break;
}
}
if ($found === true) {
chdir($location);
} else {
echo 'ERROR: Could not locate .hg directory '.PHP_EOL.PHP_EOL;
exit(2);
}
$command = 'hg blame -u -d -v "'.$filename.'" 2>&1';
$handle = popen($command, 'r');
if ($handle === false) {
echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL;
exit(2);
}
$rawContent = stream_get_contents($handle);
fclose($handle);
$blames = explode("\n", $rawContent);
chdir($cwd);
return $blames;
}//end getBlameContent()
}//end class

View File

@@ -0,0 +1,162 @@
<?php
/**
* Info report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Info report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Info implements PHP_CodeSniffer_Report
{
/**
* TRUE if this report needs error messages instead of just totals.
*
* @var boolean
*/
public $recordErrors = false;
/**
* A cache of metrics collected during the run.
*
* @var array
*/
private $_metricCache = array();
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
$metrics = $phpcsFile->getMetrics();
foreach ($metrics as $metric => $data) {
if (isset($this->_metricCache[$metric]) === false) {
$this->_metricCache[$metric] = array();
}
foreach ($data['values'] as $value => $locations) {
$locations = array_unique($locations);
$count = count($locations);
if (isset($this->_metricCache[$metric][$value]) === false) {
$this->_metricCache[$metric][$value] = $count;
} else {
$this->_metricCache[$metric][$value] += $count;
}
}
}//end foreach
return true;
}//end generateFileReport()
/**
* Prints the source of all errors and warnings.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
if (empty($this->_metricCache) === true) {
// Nothing to show.
return;
}
ksort($this->_metricCache);
echo PHP_EOL."\033[1m".'PHP CODE SNIFFER INFORMATION REPORT'."\033[0m".PHP_EOL;
echo str_repeat('-', 70).PHP_EOL;
foreach ($this->_metricCache as $metric => $values) {
$winner = '';
$winnerCount = 0;
$totalCount = 0;
foreach ($values as $value => $count) {
$totalCount += $count;
if ($count > $winnerCount) {
$winner = $value;
$winnerCount = $count;
}
}
$winPercent = round(($winnerCount / $totalCount * 100), 2);
echo "$metric: \033[4m$winner\033[0m [$winnerCount/$totalCount, $winPercent%]".PHP_EOL;
asort($values);
$values = array_reverse($values, true);
foreach ($values as $value => $count) {
if ($value === $winner) {
continue;
}
$percent = round(($count / $totalCount * 100), 2);
echo "\t$value => $count ($percent%)".PHP_EOL;
}
echo PHP_EOL;
}//end foreach
echo str_repeat('-', 70).PHP_EOL;
if ($toScreen === true && PHP_CODESNIFFER_INTERACTIVE === false) {
PHP_CodeSniffer_Reporting::printRunTime();
}
}//end generate()
}//end class

View File

@@ -0,0 +1,128 @@
<?php
/**
* Json report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Jeffrey Fisher <jeffslofish@gmail.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Json report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Jeffrey Fisher <jeffslofish@gmail.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Json implements PHP_CodeSniffer_Report
{
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
$filename = str_replace('\\', '\\\\', $report['filename']);
$filename = str_replace('"', '\"', $filename);
$filename = str_replace('/', '\/', $filename);
echo '"'.$filename.'":{';
echo '"errors":'.$report['errors'].',"warnings":'.$report['warnings'].',"messages":[';
$messages = '';
foreach ($report['messages'] as $line => $lineErrors) {
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$error['message'] = str_replace('\\', '\\\\', $error['message']);
$error['message'] = str_replace('"', '\"', $error['message']);
$error['message'] = str_replace('/', '\/', $error['message']);
$error['message'] = str_replace("\n", '\n', $error['message']);
$error['message'] = str_replace("\r", '\r', $error['message']);
$error['message'] = str_replace("\t", '\t', $error['message']);
$fixable = 'false';
if ($error['fixable'] === true) {
$fixable = 'true';
}
$messages .= '{"message":"'.$error['message'].'",';
$messages .= '"source":"'.$error['source'].'",';
$messages .= '"severity":'.$error['severity'].',';
$messages .= '"type":"'.$error['type'].'",';
$messages .= '"line":'.$line.',';
$messages .= '"column":'.$column.',';
$messages .= '"fixable":'.$fixable;
$messages .= '},';
}//end foreach
}//end foreach
}//end foreach
echo rtrim($messages, ',');
echo ']},';
return true;
}//end generateFileReport()
/**
* Generates a JSON report.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
echo '{"totals":{"errors":'.$totalErrors.',"warnings":'.$totalWarnings.',"fixable":'.$totalFixable.'},"files":{';
echo rtrim($cachedData, ',');
echo "}}";
}//end generate()
}//end class

View File

@@ -0,0 +1,149 @@
<?php
/**
* JUnit report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Oleg Lobach <oleg@lobach.info>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* JUnit report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Oleg Lobach <oleg@lobach.info>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Junit implements PHP_CodeSniffer_Report
{
/**
* A count of tests that have been performed.
*
* @var int
*/
private $_tests = 0;
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
if (count($report['messages']) === 0) {
$this->_tests++;
} else {
$this->_tests += ($report['errors'] + $report['warnings']);
}
$out = new XMLWriter;
$out->openMemory();
$out->setIndent(true);
$out->startElement('testsuite');
$out->writeAttribute('name', $report['filename']);
if (count($report['messages']) === 0) {
$out->writeAttribute('tests', 1);
$out->writeAttribute('failures', 0);
$out->startElement('testcase');
$out->writeAttribute('name', $report['filename']);
$out->endElement();
} else {
$failures = ($report['errors'] + $report['warnings']);
$out->writeAttribute('tests', $failures);
$out->writeAttribute('failures', $failures);
foreach ($report['messages'] as $line => $lineErrors) {
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$out->startElement('testcase');
$out->writeAttribute('name', $error['source'].' at '.$report['filename']." ($line:$column)");
$error['type'] = strtolower($error['type']);
if (PHP_CODESNIFFER_ENCODING !== 'utf-8') {
$error['message'] = iconv(PHP_CODESNIFFER_ENCODING, 'utf-8', $error['message']);
}
$out->startElement('failure');
$out->writeAttribute('type', $error['type']);
$out->writeAttribute('message', $error['message']);
$out->endElement();
$out->endElement();
}
}
}
}//end if
$out->endElement();
echo $out->flush();
return true;
}//end generateFileReport()
/**
* Prints all violations for processed files, in a proprietary XML format.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
$failures = ($totalErrors + $totalWarnings);
echo '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
echo '<testsuites name="PHP_CodeSniffer '.PHP_CodeSniffer::VERSION.'" tests="'.$this->_tests.'" failures="'.$failures.'">'.PHP_EOL;
echo $cachedData;
echo '</testsuites>'.PHP_EOL;
}//end generate()
}//end class

View File

@@ -0,0 +1,262 @@
<?php
/**
* Notify-send report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Christian Weiske <christian.weiske@netresearch.de>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2012-2014 Christian Weiske
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Notify-send report for PHP_CodeSniffer.
*
* Supported configuration parameters:
* - notifysend_path - Full path to notify-send cli command
* - notifysend_timeout - Timeout in milliseconds
* - notifysend_showok - Show "ok, all fine" messages (0/1)
*
* @category PHP
* @package PHP_CodeSniffer
* @author Christian Weiske <christian.weiske@netresearch.de>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2012-2014 Christian Weiske
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Notifysend implements PHP_CodeSniffer_Report
{
/**
* Notification timeout in milliseconds.
*
* @var integer
*/
protected $timeout = 3000;
/**
* Path to notify-send command.
*
* @var string
*/
protected $path = 'notify-send';
/**
* Show "ok, all fine" messages.
*
* @var boolean
*/
protected $showOk = true;
/**
* Version of installed notify-send executable.
*
* @var string
*/
protected $version = null;
/**
* A record of the last file checked.
*
* This is used in case we only checked one file and need to print
* the name/path of the file. We wont have access to the checked file list
* after the run has been completed.
*
* @var string
*/
private $_lastCheckedFile = '';
/**
* Load configuration data.
*/
public function __construct()
{
$path = PHP_CodeSniffer::getConfigData('notifysend_path');
if ($path !== null) {
$this->path = escapeshellcmd($path);
}
$timeout = PHP_CodeSniffer::getConfigData('notifysend_timeout');
if ($timeout !== null) {
$this->timeout = (int) $timeout;
}
$showOk = PHP_CodeSniffer::getConfigData('notifysend_showok');
if ($showOk !== null) {
$this->showOk = (boolean) $showOk;
}
$this->version = str_replace(
'notify-send ',
'',
exec($this->path.' --version')
);
}//end __construct()
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
// We don't need to print anything, but we want this file counted
// in the total number of checked files even if it has no errors.
$this->_lastCheckedFile = $report['filename'];
return true;
}//end generateFileReport()
/**
* Generates a summary of errors and warnings for each file processed.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
$msg = $this->generateMessage($totalFiles, $totalErrors, $totalWarnings);
if ($msg === null) {
if ($this->showOk === true) {
$this->notifyAllFine();
}
} else {
$this->notifyErrors($msg);
}
}//end generate()
/**
* Generate the error message to show to the user.
*
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
*
* @return string Error message or NULL if no error/warning found.
*/
protected function generateMessage($totalFiles, $totalErrors, $totalWarnings)
{
if ($totalErrors === 0 && $totalWarnings === 0) {
// Nothing to print.
return null;
}
$msg = '';
if ($totalFiles > 1) {
$msg .= 'Checked '.$totalFiles.' files'.PHP_EOL;
} else {
$msg .= $this->_lastCheckedFile.PHP_EOL;
}
if ($totalWarnings > 0) {
$msg .= $totalWarnings.' warnings'.PHP_EOL;
}
if ($totalErrors > 0) {
$msg .= $totalErrors.' errors'.PHP_EOL;
}
return $msg;
}//end generateMessage()
/**
* Tell the user that all is fine and no error/warning has been found.
*
* @return void
*/
protected function notifyAllFine()
{
$cmd = $this->getBasicCommand();
$cmd .= ' -i info';
$cmd .= ' "PHP CodeSniffer: Ok"';
$cmd .= ' "All fine"';
exec($cmd);
}//end notifyAllFine()
/**
* Tell the user that errors/warnings have been found.
*
* @param string $msg Message to display.
*
* @return void
*/
protected function notifyErrors($msg)
{
$cmd = $this->getBasicCommand();
$cmd .= ' -i error';
$cmd .= ' "PHP CodeSniffer: Error"';
$cmd .= ' '.escapeshellarg(trim($msg));
exec($cmd);
}//end notifyErrors()
/**
* Generate and return the basic notify-send command string to execute.
*
* @return string Shell command with common parameters.
*/
protected function getBasicCommand()
{
$cmd = $this->path;
$cmd .= ' --category dev.validate';
$cmd .= ' -h int:transient:1';
$cmd .= ' -t '.(int) $this->timeout;
if (version_compare($this->version, '0.7.3', '>=') === true) {
$cmd .= ' -a phpcs';
}
return $cmd;
}//end getBasicCommand()
}//end class

View File

@@ -0,0 +1,334 @@
<?php
/**
* Source report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Source report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Source implements PHP_CodeSniffer_Report
{
/**
* A cache of source stats collected during the run.
*
* @var array
*/
private $_sourceCache = array();
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
if ($report['errors'] === 0 && $report['warnings'] === 0) {
// Nothing to print.
return false;
}
foreach ($report['messages'] as $line => $lineErrors) {
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$source = $error['source'];
if (isset($this->_sourceCache[$source]) === false) {
if ($showSources === true) {
$parts = null;
$sniff = $source;
} else {
$parts = explode('.', $source);
if ($parts[0] === 'Internal') {
$parts[2] = $parts[1];
$parts[1] = '';
}
$parts[1] = $this->makeFriendlyName($parts[1]);
$sniff = $this->makeFriendlyName($parts[2]);
if (isset($parts[3]) === true) {
$name = $this->makeFriendlyName($parts[3]);
$name[0] = strtolower($name[0]);
$sniff .= ' '.$name;
unset($parts[3]);
}
$parts[2] = $sniff;
}//end if
$this->_sourceCache[$source] = array(
'count' => 1,
'fixable' => $error['fixable'],
'parts' => $parts,
'strlen' => strlen($sniff),
);
} else {
$this->_sourceCache[$source]['count']++;
}//end if
}//end foreach
}//end foreach
}//end foreach
return true;
}//end generateFileReport()
/**
* Prints the source of all errors and warnings.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
if (empty($this->_sourceCache) === true) {
// Nothing to show.
return;
}
// Make sure the report width isn't too big.
$maxLength = 0;
foreach ($this->_sourceCache as $source => $data) {
$maxLength = max($maxLength, $data['strlen']);
}
if ($showSources === true) {
$width = min($width, ($maxLength + 11));
} else {
$width = min($width, ($maxLength + 41));
}
$width = max($width, 70);
asort($this->_sourceCache);
$this->_sourceCache = array_reverse($this->_sourceCache);
echo PHP_EOL."\033[1mPHP CODE SNIFFER VIOLATION SOURCE SUMMARY\033[0m".PHP_EOL;
echo str_repeat('-', $width).PHP_EOL."\033[1m";
if ($showSources === true) {
if ($totalFixable > 0) {
echo ' SOURCE'.str_repeat(' ', ($width - 15)).'COUNT'.PHP_EOL;
} else {
echo 'SOURCE'.str_repeat(' ', ($width - 11)).'COUNT'.PHP_EOL;
}
} else {
if ($totalFixable > 0) {
echo ' STANDARD CATEGORY SNIFF'.str_repeat(' ', ($width - 44)).'COUNT'.PHP_EOL;
} else {
echo 'STANDARD CATEGORY SNIFF'.str_repeat(' ', ($width - 40)).'COUNT'.PHP_EOL;
}
}
echo "\033[0m".str_repeat('-', $width).PHP_EOL;
$fixableSources = 0;
if ($showSources === true) {
$maxSniffWidth = ($width - 7);
} else {
$maxSniffWidth = ($width - 37);
}
if ($totalFixable > 0) {
$maxSniffWidth -= 4;
}
foreach ($this->_sourceCache as $source => $sourceData) {
if ($totalFixable > 0) {
echo '[';
if ($sourceData['fixable'] === true) {
echo 'x';
$fixableSources++;
} else {
echo ' ';
}
echo '] ';
}
if ($showSources === true) {
if ($sourceData['strlen'] > $maxSniffWidth) {
$source = substr($source, 0, $maxSniffWidth);
}
echo $source;
if ($totalFixable > 0) {
echo str_repeat(' ', ($width - 9 - strlen($source)));
} else {
echo str_repeat(' ', ($width - 5 - strlen($source)));
}
} else {
$parts = $sourceData['parts'];
if (strlen($parts[0]) > 8) {
$parts[0] = substr($parts[0], 0, ((strlen($parts[0]) - 8) * -1));
}
echo $parts[0].str_repeat(' ', (10 - strlen($parts[0])));
$category = $parts[1];
if (strlen($category) > 18) {
$category = substr($category, 0, ((strlen($category) - 18) * -1));
}
echo $category.str_repeat(' ', (20 - strlen($category)));
$sniff = $parts[2];
if (strlen($sniff) > $maxSniffWidth) {
$sniff = substr($sniff, 0, $maxSniffWidth);
}
if ($totalFixable > 0) {
echo $sniff.str_repeat(' ', ($width - 39 - strlen($sniff)));
} else {
echo $sniff.str_repeat(' ', ($width - 35 - strlen($sniff)));
}
}//end if
echo $sourceData['count'].PHP_EOL;
}//end foreach
echo str_repeat('-', $width).PHP_EOL;
echo "\033[1m".'A TOTAL OF '.($totalErrors + $totalWarnings).' SNIFF VIOLATION';
if (($totalErrors + $totalWarnings) > 1) {
echo 'S';
}
echo ' WERE FOUND IN '.count($this->_sourceCache).' SOURCE';
if (count($this->_sourceCache) !== 1) {
echo 'S';
}
echo "\033[0m";
if ($totalFixable > 0) {
echo PHP_EOL.str_repeat('-', $width).PHP_EOL;
echo "\033[1mPHPCBF CAN FIX THE $fixableSources MARKED SOURCES AUTOMATICALLY ($totalFixable VIOLATIONS IN TOTAL)\033[0m";
}
echo PHP_EOL.str_repeat('-', $width).PHP_EOL.PHP_EOL;
if ($toScreen === true && PHP_CODESNIFFER_INTERACTIVE === false) {
PHP_CodeSniffer_Reporting::printRunTime();
}
}//end generate()
/**
* Converts a camel caps name into a readable string.
*
* @param string $name The camel caps name to convert.
*
* @return string
*/
public function makeFriendlyName($name)
{
if (trim($name) === '') {
return '';
}
$friendlyName = '';
$length = strlen($name);
$lastWasUpper = false;
$lastWasNumeric = false;
for ($i = 0; $i < $length; $i++) {
if (is_numeric($name[$i]) === true) {
if ($lastWasNumeric === false) {
$friendlyName .= ' ';
}
$lastWasUpper = false;
$lastWasNumeric = true;
} else {
$lastWasNumeric = false;
$char = strtolower($name[$i]);
if ($char === $name[$i]) {
// Lowercase.
$lastWasUpper = false;
} else {
// Uppercase.
if ($lastWasUpper === false) {
$friendlyName .= ' ';
if ($i < ($length - 1)) {
$next = $name[($i + 1)];
if (strtolower($next) === $next) {
// Next char is lowercase so it is a word boundary.
$name[$i] = strtolower($name[$i]);
}
}
}
$lastWasUpper = true;
}
}//end if
$friendlyName .= $name[$i];
}//end for
$friendlyName = trim($friendlyName);
$friendlyName[0] = strtoupper($friendlyName[0]);
return $friendlyName;
}//end makeFriendlyName()
}//end class

View File

@@ -0,0 +1,189 @@
<?php
/**
* Summary report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Summary report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Summary implements PHP_CodeSniffer_Report
{
/**
* TRUE if this report needs error messages instead of just totals.
*
* @var boolean
*/
public $recordErrors = false;
/**
* An array of process files and their error data.
*
* @var boolean
*/
private $_reportFiles = array();
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
if (PHP_CODESNIFFER_VERBOSITY === 0
&& $report['errors'] === 0
&& $report['warnings'] === 0
) {
// Nothing to print.
return false;
}
$this->_reportFiles[$report['filename']] = array(
'errors' => $report['errors'],
'warnings' => $report['warnings'],
'strlen' => strlen($report['filename']),
);
return true;
}//end generateFileReport()
/**
* Generates a summary of errors and warnings for each file processed.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
if (empty($this->_reportFiles) === true) {
return;
}
// Make sure the report width isn't too big.
$maxLength = 0;
foreach ($this->_reportFiles as $file => $data) {
$maxLength = max($maxLength, $data['strlen']);
}
$width = min($width, ($maxLength + 21));
$width = max($width, 70);
echo PHP_EOL."\033[1m".'PHP CODE SNIFFER REPORT SUMMARY'."\033[0m".PHP_EOL;
echo str_repeat('-', $width).PHP_EOL;
echo "\033[1m".'FILE'.str_repeat(' ', ($width - 20)).'ERRORS WARNINGS'."\033[0m".PHP_EOL;
echo str_repeat('-', $width).PHP_EOL;
foreach ($this->_reportFiles as $file => $data) {
$padding = ($width - 18 - $data['strlen']);
if ($padding < 0) {
$file = '...'.substr($file, (($padding * -1) + 3));
$padding = 0;
}
echo $file.str_repeat(' ', $padding).' ';
if ($data['errors'] !== 0) {
echo "\033[31m".$data['errors']."\033[0m";
echo str_repeat(' ', (8 - strlen((string) $data['errors'])));
} else {
echo '0 ';
}
if ($data['warnings'] !== 0) {
echo "\033[33m".$data['warnings']."\033[0m";
} else {
echo '0';
}
echo PHP_EOL;
}//end foreach
echo str_repeat('-', $width).PHP_EOL;
echo "\033[1mA TOTAL OF $totalErrors ERROR";
if ($totalErrors !== 1) {
echo 'S';
}
echo ' AND '.$totalWarnings.' WARNING';
if ($totalWarnings !== 1) {
echo 'S';
}
echo ' WERE FOUND IN '.$totalFiles.' FILE';
if ($totalFiles !== 1) {
echo 'S';
}
echo "\033[0m";
if ($totalFixable > 0) {
echo PHP_EOL.str_repeat('-', $width).PHP_EOL;
echo "\033[1mPHPCBF CAN FIX $totalFixable OF THESE SNIFF VIOLATIONS AUTOMATICALLY\033[0m";
}
echo PHP_EOL.str_repeat('-', $width).PHP_EOL.PHP_EOL;
if ($toScreen === true && PHP_CODESNIFFER_INTERACTIVE === false) {
PHP_CodeSniffer_Reporting::printRunTime();
}
}//end generate()
}//end class

View File

@@ -0,0 +1,90 @@
<?php
/**
* Svnblame report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Svnblame report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Svnblame extends PHP_CodeSniffer_Reports_VersionControl
{
/**
* The name of the report we want in the output
*
* @var string
*/
protected $reportName = 'SVN';
/**
* Extract the author from a blame line.
*
* @param string $line Line to parse.
*
* @return mixed string or false if impossible to recover.
*/
protected function getAuthor($line)
{
$blameParts = array();
preg_match('|\s*([^\s]+)\s+([^\s]+)|', $line, $blameParts);
if (isset($blameParts[2]) === false) {
return false;
}
return $blameParts[2];
}//end getAuthor()
/**
* Gets the blame output.
*
* @param string $filename File to blame.
*
* @return array
*/
protected function getBlameContent($filename)
{
$command = 'svn blame "'.$filename.'" 2>&1';
$handle = popen($command, 'r');
if ($handle === false) {
echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL;
exit(2);
}
$rawContent = stream_get_contents($handle);
fclose($handle);
$blames = explode("\n", $rawContent);
return $blames;
}//end getBlameContent()
}//end class

View File

@@ -0,0 +1,342 @@
<?php
/**
* Version control report base class for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Ben Selby <benmatselby@gmail.com>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Version control report base class for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Ben Selby <benmatselby@gmail.com>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: 1.2.2
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
abstract class PHP_CodeSniffer_Reports_VersionControl implements PHP_CodeSniffer_Report
{
/**
* The name of the report we want in the output.
*
* @var string
*/
protected $reportName = 'VERSION CONTROL';
/**
* A cache of author stats collected during the run.
*
* @var array
*/
private $_authorCache = array();
/**
* A cache of blame stats collected during the run.
*
* @var array
*/
private $_praiseCache = array();
/**
* A cache of source stats collected during the run.
*
* @var array
*/
private $_sourceCache = array();
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
$blames = $this->getBlameContent($report['filename']);
foreach ($report['messages'] as $line => $lineErrors) {
$author = 'Unknown';
if (isset($blames[($line - 1)]) === true) {
$blameAuthor = $this->getAuthor($blames[($line - 1)]);
if ($blameAuthor !== false) {
$author = $blameAuthor;
}
}
if (isset($this->_authorCache[$author]) === false) {
$this->_authorCache[$author] = 0;
$this->_praiseCache[$author] = array(
'good' => 0,
'bad' => 0,
);
}
$this->_praiseCache[$author]['bad']++;
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$this->_authorCache[$author]++;
if ($showSources === true) {
$source = $error['source'];
if (isset($this->_sourceCache[$author][$source]) === false) {
$this->_sourceCache[$author][$source] = array(
'count' => 1,
'fixable' => $error['fixable'],
);
} else {
$this->_sourceCache[$author][$source]['count']++;
}
}
}
}
unset($blames[($line - 1)]);
}//end foreach
// No go through and give the authors some credit for
// all the lines that do not have errors.
foreach ($blames as $line) {
$author = $this->getAuthor($line);
if ($author === false) {
$author = 'Unknown';
}
if (isset($this->_authorCache[$author]) === false) {
// This author doesn't have any errors.
if (PHP_CODESNIFFER_VERBOSITY === 0) {
continue;
}
$this->_authorCache[$author] = 0;
$this->_praiseCache[$author] = array(
'good' => 0,
'bad' => 0,
);
}
$this->_praiseCache[$author]['good']++;
}//end foreach
return true;
}//end generateFileReport()
/**
* Prints the author of all errors and warnings, as given by "version control blame".
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
$errorsShown = ($totalErrors + $totalWarnings);
if ($errorsShown === 0) {
// Nothing to show.
return;
}
// Make sure the report width isn't too big.
$maxLength = 0;
foreach ($this->_authorCache as $author => $count) {
$maxLength = max($maxLength, strlen($author));
if ($showSources === true && isset($this->_sourceCache[$author]) === true) {
foreach ($this->_sourceCache[$author] as $source => $sourceData) {
if ($source === 'count') {
continue;
}
$maxLength = max($maxLength, (strlen($source) + 9));
}
}
}
$width = min($width, ($maxLength + 30));
$width = max($width, 70);
arsort($this->_authorCache);
echo PHP_EOL."\033[1m".'PHP CODE SNIFFER '.$this->reportName.' BLAME SUMMARY'."\033[0m".PHP_EOL;
echo str_repeat('-', $width).PHP_EOL."\033[1m";
if ($showSources === true) {
echo 'AUTHOR SOURCE'.str_repeat(' ', ($width - 43)).'(Author %) (Overall %) COUNT'.PHP_EOL;
echo str_repeat('-', $width).PHP_EOL;
} else {
echo 'AUTHOR'.str_repeat(' ', ($width - 34)).'(Author %) (Overall %) COUNT'.PHP_EOL;
echo str_repeat('-', $width).PHP_EOL;
}
echo "\033[0m";
if ($showSources === true) {
$maxSniffWidth = ($width - 15);
if ($totalFixable > 0) {
$maxSniffWidth -= 4;
}
}
$fixableSources = 0;
foreach ($this->_authorCache as $author => $count) {
if ($this->_praiseCache[$author]['good'] === 0) {
$percent = 0;
} else {
$total = ($this->_praiseCache[$author]['bad'] + $this->_praiseCache[$author]['good']);
$percent = round(($this->_praiseCache[$author]['bad'] / $total * 100), 2);
}
$overallPercent = '('.round((($count / $errorsShown) * 100), 2).')';
$authorPercent = '('.$percent.')';
$line = str_repeat(' ', (6 - strlen($count))).$count;
$line = str_repeat(' ', (12 - strlen($overallPercent))).$overallPercent.$line;
$line = str_repeat(' ', (11 - strlen($authorPercent))).$authorPercent.$line;
$line = $author.str_repeat(' ', ($width - strlen($author) - strlen($line))).$line;
if ($showSources === true) {
$line = "\033[1m$line\033[0m";
}
echo $line.PHP_EOL;
if ($showSources === true && isset($this->_sourceCache[$author]) === true) {
$errors = $this->_sourceCache[$author];
asort($errors);
$errors = array_reverse($errors);
foreach ($errors as $source => $sourceData) {
if ($source === 'count') {
continue;
}
$count = $sourceData['count'];
$srcLength = strlen($source);
if ($srcLength > $maxSniffWidth) {
$source = substr($source, 0, $maxSniffWidth);
}
$line = str_repeat(' ', (5 - strlen($count))).$count;
echo ' ';
if ($totalFixable > 0) {
echo '[';
if ($sourceData['fixable'] === true) {
echo 'x';
$fixableSources++;
} else {
echo ' ';
}
echo '] ';
}
echo $source;
if ($totalFixable > 0) {
echo str_repeat(' ', ($width - 18 - strlen($source)));
} else {
echo str_repeat(' ', ($width - 14 - strlen($source)));
}
echo $line.PHP_EOL;
}//end foreach
}//end if
}//end foreach
echo str_repeat('-', $width).PHP_EOL;
echo "\033[1m".'A TOTAL OF '.$errorsShown.' SNIFF VIOLATION';
if ($errorsShown !== 1) {
echo 'S';
}
echo ' WERE COMMITTED BY '.count($this->_authorCache).' AUTHOR';
if (count($this->_authorCache) !== 1) {
echo 'S';
}
echo "\033[0m";
if ($totalFixable > 0) {
if ($showSources === true) {
echo PHP_EOL.str_repeat('-', $width).PHP_EOL;
echo "\033[1mPHPCBF CAN FIX THE $fixableSources MARKED SOURCES AUTOMATICALLY ($totalFixable VIOLATIONS IN TOTAL)\033[0m";
} else {
echo PHP_EOL.str_repeat('-', $width).PHP_EOL;
echo "\033[1mPHPCBF CAN FIX $totalFixable OF THESE SNIFF VIOLATIONS AUTOMATICALLY\033[0m";
}
}
echo PHP_EOL.str_repeat('-', $width).PHP_EOL.PHP_EOL;
if ($toScreen === true && PHP_CODESNIFFER_INTERACTIVE === false) {
PHP_CodeSniffer_Reporting::printRunTime();
}
}//end generate()
/**
* Extract the author from a blame line.
*
* @param string $line Line to parse.
*
* @return mixed string or false if impossible to recover.
*/
abstract protected function getAuthor($line);
/**
* Gets the blame output.
*
* @param string $filename File to blame.
*
* @return array
*/
abstract protected function getBlameContent($filename);
}//end class

View File

@@ -0,0 +1,132 @@
<?php
/**
* Xml report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Xml report for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Gabriele Santini <gsantini@sqli.com>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2009-2014 SQLI <www.sqli.com>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class PHP_CodeSniffer_Reports_Xml implements PHP_CodeSniffer_Report
{
/**
* Generate a partial report for a single processed file.
*
* Function should return TRUE if it printed or stored data about the file
* and FALSE if it ignored the file. Returning TRUE indicates that the file and
* its data should be counted in the grand totals.
*
* @param array $report Prepared report data.
* @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
*
* @return boolean
*/
public function generateFileReport(
$report,
PHP_CodeSniffer_File $phpcsFile,
$showSources=false,
$width=80
) {
$out = new XMLWriter;
$out->openMemory();
$out->setIndent(true);
if ($report['errors'] === 0 && $report['warnings'] === 0) {
// Nothing to print.
return false;
}
$out->startElement('file');
$out->writeAttribute('name', $report['filename']);
$out->writeAttribute('errors', $report['errors']);
$out->writeAttribute('warnings', $report['warnings']);
$out->writeAttribute('fixable', $report['fixable']);
foreach ($report['messages'] as $line => $lineErrors) {
foreach ($lineErrors as $column => $colErrors) {
foreach ($colErrors as $error) {
$error['type'] = strtolower($error['type']);
if (PHP_CODESNIFFER_ENCODING !== 'utf-8') {
$error['message'] = iconv(PHP_CODESNIFFER_ENCODING, 'utf-8', $error['message']);
}
$out->startElement($error['type']);
$out->writeAttribute('line', $line);
$out->writeAttribute('column', $column);
$out->writeAttribute('source', $error['source']);
$out->writeAttribute('severity', $error['severity']);
$out->writeAttribute('fixable', (int) $error['fixable']);
$out->text($error['message']);
$out->endElement();
}
}
}//end foreach
$out->endElement();
echo $out->flush();
return true;
}//end generateFileReport()
/**
* Prints all violations for processed files, in a proprietary XML format.
*
* @param string $cachedData Any partial report data that was returned from
* generateFileReport during the run.
* @param int $totalFiles Total number of files processed during the run.
* @param int $totalErrors Total number of errors found during the run.
* @param int $totalWarnings Total number of warnings found during the run.
* @param int $totalFixable Total number of problems that can be fixed.
* @param boolean $showSources Show sources?
* @param int $width Maximum allowed line width.
* @param boolean $toScreen Is the report being printed to screen?
*
* @return void
*/
public function generate(
$cachedData,
$totalFiles,
$totalErrors,
$totalWarnings,
$totalFixable,
$showSources=false,
$width=80,
$toScreen=true
) {
echo '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
echo '<phpcs version="'.PHP_CodeSniffer::VERSION.'">'.PHP_EOL;
echo $cachedData;
echo '</phpcs>'.PHP_EOL;
}//end generate()
}//end class

View File

@@ -0,0 +1,94 @@
<?php
/**
* Represents a PHP_CodeSniffer sniff for sniffing coding standards.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Represents a PHP_CodeSniffer sniff for sniffing coding standards.
*
* A sniff registers what token types it wishes to listen for, then, when
* PHP_CodeSniffer encounters that token, the sniff is invoked and passed
* information about where the token was found in the stack, and the
* PHP_CodeSniffer file in which the token was found.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
interface PHP_CodeSniffer_Sniff
{
/**
* Registers the tokens that this sniff wants to listen for.
*
* An example return value for a sniff that wants to listen for whitespace
* and any comments would be:
*
* <code>
* return array(
* T_WHITESPACE,
* T_DOC_COMMENT,
* T_COMMENT,
* );
* </code>
*
* @return int[]
* @see Tokens.php
*/
public function register();
/**
* Called when one of the token types that this sniff is listening for
* is found.
*
* The stackPtr variable indicates where in the stack the token was found.
* A sniff can acquire information this token, along with all the other
* tokens within the stack by first acquiring the token stack:
*
* <code>
* $tokens = $phpcsFile->getTokens();
* echo 'Encountered a '.$tokens[$stackPtr]['type'].' token';
* echo 'token information: ';
* print_r($tokens[$stackPtr]);
* </code>
*
* If the sniff discovers an anomaly in the code, they can raise an error
* by calling addError() on the PHP_CodeSniffer_File object, specifying an error
* message and the position of the offending token:
*
* <code>
* $phpcsFile->addError('Encountered an error', $stackPtr);
* </code>
*
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the
* token was found.
* @param int $stackPtr The position in the PHP_CodeSniffer
* file's token stack where the token
* was found.
*
* @return void|int Optionally returns a stack pointer. The sniff will not be
* called again on the current file until the returned stack
* pointer is reached. Return (count($tokens) + 1) to skip
* the rest of the file.
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr);
}//end interface

View File

@@ -0,0 +1,962 @@
<?php
/**
* Processes pattern strings and checks that the code conforms to the pattern.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
if (class_exists('PHP_CodeSniffer_Standards_IncorrectPatternException', true) === false) {
$error = 'Class PHP_CodeSniffer_Standards_IncorrectPatternException not found';
throw new PHP_CodeSniffer_Exception($error);
}
/**
* Processes pattern strings and checks that the code conforms to the pattern.
*
* This test essentially checks that code is correctly formatted with whitespace.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
abstract class PHP_CodeSniffer_Standards_AbstractPatternSniff implements PHP_CodeSniffer_Sniff
{
/**
* If true, comments will be ignored if they are found in the code.
*
* @var boolean
*/
public $ignoreComments = false;
/**
* The current file being checked.
*
* @var string
*/
protected $currFile = '';
/**
* The parsed patterns array.
*
* @var array
*/
private $_parsedPatterns = array();
/**
* Tokens that this sniff wishes to process outside of the patterns.
*
* @var array(int)
* @see registerSupplementary()
* @see processSupplementary()
*/
private $_supplementaryTokens = array();
/**
* Positions in the stack where errors have occurred.
*
* @var array()
*/
private $_errorPos = array();
/**
* Constructs a PHP_CodeSniffer_Standards_AbstractPatternSniff.
*
* @param boolean $ignoreComments If true, comments will be ignored.
*/
public function __construct($ignoreComments=null)
{
// This is here for backwards compatibility.
if ($ignoreComments !== null) {
$this->ignoreComments = $ignoreComments;
}
$this->_supplementaryTokens = $this->registerSupplementary();
}//end __construct()
/**
* Registers the tokens to listen to.
*
* Classes extending <i>AbstractPatternTest</i> should implement the
* <i>getPatterns()</i> method to register the patterns they wish to test.
*
* @return int[]
* @see process()
*/
public final function register()
{
$listenTypes = array();
$patterns = $this->getPatterns();
foreach ($patterns as $pattern) {
$parsedPattern = $this->_parse($pattern);
// Find a token position in the pattern that we can use
// for a listener token.
$pos = $this->_getListenerTokenPos($parsedPattern);
$tokenType = $parsedPattern[$pos]['token'];
$listenTypes[] = $tokenType;
$patternArray = array(
'listen_pos' => $pos,
'pattern' => $parsedPattern,
'pattern_code' => $pattern,
);
if (isset($this->_parsedPatterns[$tokenType]) === false) {
$this->_parsedPatterns[$tokenType] = array();
}
$this->_parsedPatterns[$tokenType][] = $patternArray;
}//end foreach
return array_unique(array_merge($listenTypes, $this->_supplementaryTokens));
}//end register()
/**
* Returns the token types that the specified pattern is checking for.
*
* Returned array is in the format:
* <code>
* array(
* T_WHITESPACE => 0, // 0 is the position where the T_WHITESPACE token
* // should occur in the pattern.
* );
* </code>
*
* @param array $pattern The parsed pattern to find the acquire the token
* types from.
*
* @return array<int, int>
*/
private function _getPatternTokenTypes($pattern)
{
$tokenTypes = array();
foreach ($pattern as $pos => $patternInfo) {
if ($patternInfo['type'] === 'token') {
if (isset($tokenTypes[$patternInfo['token']]) === false) {
$tokenTypes[$patternInfo['token']] = $pos;
}
}
}
return $tokenTypes;
}//end _getPatternTokenTypes()
/**
* Returns the position in the pattern that this test should register as
* a listener for the pattern.
*
* @param array $pattern The pattern to acquire the listener for.
*
* @return int The position in the pattern that this test should register
* as the listener.
* @throws PHP_CodeSniffer_Exception If we could not determine a token
* to listen for.
*/
private function _getListenerTokenPos($pattern)
{
$tokenTypes = $this->_getPatternTokenTypes($pattern);
$tokenCodes = array_keys($tokenTypes);
$token = PHP_CodeSniffer_Tokens::getHighestWeightedToken($tokenCodes);
// If we could not get a token.
if ($token === false) {
$error = 'Could not determine a token to listen for';
throw new PHP_CodeSniffer_Exception($error);
}
return $tokenTypes[$token];
}//end _getListenerTokenPos()
/**
* Processes the test.
*
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the
* token occurred.
* @param int $stackPtr The position in the tokens stack
* where the listening token type was
* found.
*
* @return void
* @see register()
*/
public final function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$file = $phpcsFile->getFilename();
if ($this->currFile !== $file) {
// We have changed files, so clean up.
$this->_errorPos = array();
$this->currFile = $file;
}
$tokens = $phpcsFile->getTokens();
if (in_array($tokens[$stackPtr]['code'], $this->_supplementaryTokens) === true) {
$this->processSupplementary($phpcsFile, $stackPtr);
}
$type = $tokens[$stackPtr]['code'];
// If the type is not set, then it must have been a token registered
// with registerSupplementary().
if (isset($this->_parsedPatterns[$type]) === false) {
return;
}
$allErrors = array();
// Loop over each pattern that is listening to the current token type
// that we are processing.
foreach ($this->_parsedPatterns[$type] as $patternInfo) {
// If processPattern returns false, then the pattern that we are
// checking the code with must not be designed to check that code.
$errors = $this->processPattern($patternInfo, $phpcsFile, $stackPtr);
if ($errors === false) {
// The pattern didn't match.
continue;
} else if (empty($errors) === true) {
// The pattern matched, but there were no errors.
break;
}
foreach ($errors as $stackPtr => $error) {
if (isset($this->_errorPos[$stackPtr]) === false) {
$this->_errorPos[$stackPtr] = true;
$allErrors[$stackPtr] = $error;
}
}
}
foreach ($allErrors as $stackPtr => $error) {
$phpcsFile->addError($error, $stackPtr, 'Found');
}
}//end process()
/**
* Processes the pattern and verifies the code at $stackPtr.
*
* @param array $patternInfo Information about the pattern used
* for checking, which includes are
* parsed token representation of the
* pattern.
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the
* token occurred.
* @param int $stackPtr The position in the tokens stack where
* the listening token type was found.
*
* @return array
*/
protected function processPattern(
$patternInfo,
PHP_CodeSniffer_File $phpcsFile,
$stackPtr
) {
$tokens = $phpcsFile->getTokens();
$pattern = $patternInfo['pattern'];
$patternCode = $patternInfo['pattern_code'];
$errors = array();
$found = '';
$ignoreTokens = array(T_WHITESPACE);
if ($this->ignoreComments === true) {
$ignoreTokens
= array_merge($ignoreTokens, PHP_CodeSniffer_Tokens::$commentTokens);
}
$origStackPtr = $stackPtr;
$hasError = false;
if ($patternInfo['listen_pos'] > 0) {
$stackPtr--;
for ($i = ($patternInfo['listen_pos'] - 1); $i >= 0; $i--) {
if ($pattern[$i]['type'] === 'token') {
if ($pattern[$i]['token'] === T_WHITESPACE) {
if ($tokens[$stackPtr]['code'] === T_WHITESPACE) {
$found = $tokens[$stackPtr]['content'].$found;
}
// Only check the size of the whitespace if this is not
// the first token. We don't care about the size of
// leading whitespace, just that there is some.
if ($i !== 0) {
if ($tokens[$stackPtr]['content'] !== $pattern[$i]['value']) {
$hasError = true;
}
}
} else {
// Check to see if this important token is the same as the
// previous important token in the pattern. If it is not,
// then the pattern cannot be for this piece of code.
$prev = $phpcsFile->findPrevious(
$ignoreTokens,
$stackPtr,
null,
true
);
if ($prev === false
|| $tokens[$prev]['code'] !== $pattern[$i]['token']
) {
return false;
}
// If we skipped past some whitespace tokens, then add them
// to the found string.
$tokenContent = $phpcsFile->getTokensAsString(
($prev + 1),
($stackPtr - $prev - 1)
);
$found = $tokens[$prev]['content'].$tokenContent.$found;
if (isset($pattern[($i - 1)]) === true
&& $pattern[($i - 1)]['type'] === 'skip'
) {
$stackPtr = $prev;
} else {
$stackPtr = ($prev - 1);
}
}//end if
} else if ($pattern[$i]['type'] === 'skip') {
// Skip to next piece of relevant code.
if ($pattern[$i]['to'] === 'parenthesis_closer') {
$to = 'parenthesis_opener';
} else {
$to = 'scope_opener';
}
// Find the previous opener.
$next = $phpcsFile->findPrevious(
$ignoreTokens,
$stackPtr,
null,
true
);
if ($next === false || isset($tokens[$next][$to]) === false) {
// If there was not opener, then we must be
// using the wrong pattern.
return false;
}
if ($to === 'parenthesis_opener') {
$found = '{'.$found;
} else {
$found = '('.$found;
}
$found = '...'.$found;
// Skip to the opening token.
$stackPtr = ($tokens[$next][$to] - 1);
} else if ($pattern[$i]['type'] === 'string') {
$found = 'abc';
} else if ($pattern[$i]['type'] === 'newline') {
if ($this->ignoreComments === true
&& isset(PHP_CodeSniffer_Tokens::$commentTokens[$tokens[$stackPtr]['code']]) === true
) {
$startComment = $phpcsFile->findPrevious(
PHP_CodeSniffer_Tokens::$commentTokens,
($stackPtr - 1),
null,
true
);
if ($tokens[$startComment]['line'] !== $tokens[($startComment + 1)]['line']) {
$startComment++;
}
$tokenContent = $phpcsFile->getTokensAsString(
$startComment,
($stackPtr - $startComment + 1)
);
$found = $tokenContent.$found;
$stackPtr = ($startComment - 1);
}
if ($tokens[$stackPtr]['code'] === T_WHITESPACE) {
if ($tokens[$stackPtr]['content'] !== $phpcsFile->eolChar) {
$found = $tokens[$stackPtr]['content'].$found;
// This may just be an indent that comes after a newline
// so check the token before to make sure. If it is a newline, we
// can ignore the error here.
if (($tokens[($stackPtr - 1)]['content'] !== $phpcsFile->eolChar)
&& ($this->ignoreComments === true
&& isset(PHP_CodeSniffer_Tokens::$commentTokens[$tokens[($stackPtr - 1)]['code']]) === false)
) {
$hasError = true;
} else {
$stackPtr--;
}
} else {
$found = 'EOL'.$found;
}
} else {
$found = $tokens[$stackPtr]['content'].$found;
$hasError = true;
}//end if
if ($hasError === false && $pattern[($i - 1)]['type'] !== 'newline') {
// Make sure they only have 1 newline.
$prev = $phpcsFile->findPrevious($ignoreTokens, ($stackPtr - 1), null, true);
if ($prev !== false && $tokens[$prev]['line'] !== $tokens[$stackPtr]['line']) {
$hasError = true;
}
}
}//end if
}//end for
}//end if
$stackPtr = $origStackPtr;
$lastAddedStackPtr = null;
$patternLen = count($pattern);
for ($i = $patternInfo['listen_pos']; $i < $patternLen; $i++) {
if (isset($tokens[$stackPtr]) === false) {
break;
}
if ($pattern[$i]['type'] === 'token') {
if ($pattern[$i]['token'] === T_WHITESPACE) {
if ($this->ignoreComments === true) {
// If we are ignoring comments, check to see if this current
// token is a comment. If so skip it.
if (isset(PHP_CodeSniffer_Tokens::$commentTokens[$tokens[$stackPtr]['code']]) === true) {
continue;
}
// If the next token is a comment, the we need to skip the
// current token as we should allow a space before a
// comment for readability.
if (isset($tokens[($stackPtr + 1)]) === true
&& isset(PHP_CodeSniffer_Tokens::$commentTokens[$tokens[($stackPtr + 1)]['code']]) === true
) {
continue;
}
}
$tokenContent = '';
if ($tokens[$stackPtr]['code'] === T_WHITESPACE) {
if (isset($pattern[($i + 1)]) === false) {
// This is the last token in the pattern, so just compare
// the next token of content.
$tokenContent = $tokens[$stackPtr]['content'];
} else {
// Get all the whitespace to the next token.
$next = $phpcsFile->findNext(
PHP_CodeSniffer_Tokens::$emptyTokens,
$stackPtr,
null,
true
);
$tokenContent = $phpcsFile->getTokensAsString(
$stackPtr,
($next - $stackPtr)
);
$lastAddedStackPtr = $stackPtr;
$stackPtr = $next;
}//end if
if ($stackPtr !== $lastAddedStackPtr) {
$found .= $tokenContent;
}
} else {
if ($stackPtr !== $lastAddedStackPtr) {
$found .= $tokens[$stackPtr]['content'];
$lastAddedStackPtr = $stackPtr;
}
}//end if
if (isset($pattern[($i + 1)]) === true
&& $pattern[($i + 1)]['type'] === 'skip'
) {
// The next token is a skip token, so we just need to make
// sure the whitespace we found has *at least* the
// whitespace required.
if (strpos($tokenContent, $pattern[$i]['value']) !== 0) {
$hasError = true;
}
} else {
if ($tokenContent !== $pattern[$i]['value']) {
$hasError = true;
}
}
} else {
// Check to see if this important token is the same as the
// next important token in the pattern. If it is not, then
// the pattern cannot be for this piece of code.
$next = $phpcsFile->findNext(
$ignoreTokens,
$stackPtr,
null,
true
);
if ($next === false
|| $tokens[$next]['code'] !== $pattern[$i]['token']
) {
// The next important token did not match the pattern.
return false;
}
if ($lastAddedStackPtr !== null) {
if (($tokens[$next]['code'] === T_OPEN_CURLY_BRACKET
|| $tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET)
&& isset($tokens[$next]['scope_condition']) === true
&& $tokens[$next]['scope_condition'] > $lastAddedStackPtr
) {
// This is a brace, but the owner of it is after the current
// token, which means it does not belong to any token in
// our pattern. This means the pattern is not for us.
return false;
}
if (($tokens[$next]['code'] === T_OPEN_PARENTHESIS
|| $tokens[$next]['code'] === T_CLOSE_PARENTHESIS)
&& isset($tokens[$next]['parenthesis_owner']) === true
&& $tokens[$next]['parenthesis_owner'] > $lastAddedStackPtr
) {
// This is a bracket, but the owner of it is after the current
// token, which means it does not belong to any token in
// our pattern. This means the pattern is not for us.
return false;
}
}//end if
// If we skipped past some whitespace tokens, then add them
// to the found string.
if (($next - $stackPtr) > 0) {
$hasComment = false;
for ($j = $stackPtr; $j < $next; $j++) {
$found .= $tokens[$j]['content'];
if (isset(PHP_CodeSniffer_Tokens::$commentTokens[$tokens[$j]['code']]) === true) {
$hasComment = true;
}
}
// If we are not ignoring comments, this additional
// whitespace or comment is not allowed. If we are
// ignoring comments, there needs to be at least one
// comment for this to be allowed.
if ($this->ignoreComments === false
|| ($this->ignoreComments === true
&& $hasComment === false)
) {
$hasError = true;
}
// Even when ignoring comments, we are not allowed to include
// newlines without the pattern specifying them, so
// everything should be on the same line.
if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) {
$hasError = true;
}
}//end if
if ($next !== $lastAddedStackPtr) {
$found .= $tokens[$next]['content'];
$lastAddedStackPtr = $next;
}
if (isset($pattern[($i + 1)]) === true
&& $pattern[($i + 1)]['type'] === 'skip'
) {
$stackPtr = $next;
} else {
$stackPtr = ($next + 1);
}
}//end if
} else if ($pattern[$i]['type'] === 'skip') {
if ($pattern[$i]['to'] === 'unknown') {
$next = $phpcsFile->findNext(
$pattern[($i + 1)]['token'],
$stackPtr
);
if ($next === false) {
// Couldn't find the next token, so we must
// be using the wrong pattern.
return false;
}
$found .= '...';
$stackPtr = $next;
} else {
// Find the previous opener.
$next = $phpcsFile->findPrevious(
PHP_CodeSniffer_Tokens::$blockOpeners,
$stackPtr
);
if ($next === false
|| isset($tokens[$next][$pattern[$i]['to']]) === false
) {
// If there was not opener, then we must
// be using the wrong pattern.
return false;
}
$found .= '...';
if ($pattern[$i]['to'] === 'parenthesis_closer') {
$found .= ')';
} else {
$found .= '}';
}
// Skip to the closing token.
$stackPtr = ($tokens[$next][$pattern[$i]['to']] + 1);
}//end if
} else if ($pattern[$i]['type'] === 'string') {
if ($tokens[$stackPtr]['code'] !== T_STRING) {
$hasError = true;
}
if ($stackPtr !== $lastAddedStackPtr) {
$found .= 'abc';
$lastAddedStackPtr = $stackPtr;
}
$stackPtr++;
} else if ($pattern[$i]['type'] === 'newline') {
// Find the next token that contains a newline character.
$newline = 0;
for ($j = $stackPtr; $j < $phpcsFile->numTokens; $j++) {
if (strpos($tokens[$j]['content'], $phpcsFile->eolChar) !== false) {
$newline = $j;
break;
}
}
if ($newline === 0) {
// We didn't find a newline character in the rest of the file.
$next = ($phpcsFile->numTokens - 1);
$hasError = true;
} else {
if ($this->ignoreComments === false) {
// The newline character cannot be part of a comment.
if (isset(PHP_CodeSniffer_Tokens::$commentTokens[$tokens[$newline]['code']]) === true) {
$hasError = true;
}
}
if ($newline === $stackPtr) {
$next = ($stackPtr + 1);
} else {
// Check that there were no significant tokens that we
// skipped over to find our newline character.
$next = $phpcsFile->findNext(
$ignoreTokens,
$stackPtr,
null,
true
);
if ($next < $newline) {
// We skipped a non-ignored token.
$hasError = true;
} else {
$next = ($newline + 1);
}
}
}//end if
if ($stackPtr !== $lastAddedStackPtr) {
$found .= $phpcsFile->getTokensAsString(
$stackPtr,
($next - $stackPtr)
);
$diff = ($next - $stackPtr);
$lastAddedStackPtr = ($next - 1);
}
$stackPtr = $next;
}//end if
}//end for
if ($hasError === true) {
$error = $this->prepareError($found, $patternCode);
$errors[$origStackPtr] = $error;
}
return $errors;
}//end processPattern()
/**
* Prepares an error for the specified patternCode.
*
* @param string $found The actual found string in the code.
* @param string $patternCode The expected pattern code.
*
* @return string The error message.
*/
protected function prepareError($found, $patternCode)
{
$found = str_replace("\r\n", '\n', $found);
$found = str_replace("\n", '\n', $found);
$found = str_replace("\r", '\n', $found);
$found = str_replace("\t", '\t', $found);
$found = str_replace('EOL', '\n', $found);
$expected = str_replace('EOL', '\n', $patternCode);
$error = "Expected \"$expected\"; found \"$found\"";
return $error;
}//end prepareError()
/**
* Returns the patterns that should be checked.
*
* @return string[]
*/
protected abstract function getPatterns();
/**
* Registers any supplementary tokens that this test might wish to process.
*
* A sniff may wish to register supplementary tests when it wishes to group
* an arbitrary validation that cannot be performed using a pattern, with
* other pattern tests.
*
* @return int[]
* @see processSupplementary()
*/
protected function registerSupplementary()
{
return array();
}//end registerSupplementary()
/**
* Processes any tokens registered with registerSupplementary().
*
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where to
* process the skip.
* @param int $stackPtr The position in the tokens stack to
* process.
*
* @return void
* @see registerSupplementary()
*/
protected function processSupplementary(
PHP_CodeSniffer_File $phpcsFile,
$stackPtr
) {
}//end processSupplementary()
/**
* Parses a pattern string into an array of pattern steps.
*
* @param string $pattern The pattern to parse.
*
* @return array The parsed pattern array.
* @see _createSkipPattern()
* @see _createTokenPattern()
*/
private function _parse($pattern)
{
$patterns = array();
$length = strlen($pattern);
$lastToken = 0;
$firstToken = 0;
for ($i = 0; $i < $length; $i++) {
$specialPattern = false;
$isLastChar = ($i === ($length - 1));
$oldFirstToken = $firstToken;
if (substr($pattern, $i, 3) === '...') {
// It's a skip pattern. The skip pattern requires the
// content of the token in the "from" position and the token
// to skip to.
$specialPattern = $this->_createSkipPattern($pattern, ($i - 1));
$lastToken = ($i - $firstToken);
$firstToken = ($i + 3);
$i = ($i + 2);
if ($specialPattern['to'] !== 'unknown') {
$firstToken++;
}
} else if (substr($pattern, $i, 3) === 'abc') {
$specialPattern = array('type' => 'string');
$lastToken = ($i - $firstToken);
$firstToken = ($i + 3);
$i = ($i + 2);
} else if (substr($pattern, $i, 3) === 'EOL') {
$specialPattern = array('type' => 'newline');
$lastToken = ($i - $firstToken);
$firstToken = ($i + 3);
$i = ($i + 2);
}//end if
if ($specialPattern !== false || $isLastChar === true) {
// If we are at the end of the string, don't worry about a limit.
if ($isLastChar === true) {
// Get the string from the end of the last skip pattern, if any,
// to the end of the pattern string.
$str = substr($pattern, $oldFirstToken);
} else {
// Get the string from the end of the last special pattern,
// if any, to the start of this special pattern.
if ($lastToken === 0) {
// Note that if the last special token was zero characters ago,
// there will be nothing to process so we can skip this bit.
// This happens if you have something like: EOL... in your pattern.
$str = '';
} else {
$str = substr($pattern, $oldFirstToken, $lastToken);
}
}
if ($str !== '') {
$tokenPatterns = $this->_createTokenPattern($str);
foreach ($tokenPatterns as $tokenPattern) {
$patterns[] = $tokenPattern;
}
}
// Make sure we don't skip the last token.
if ($isLastChar === false && $i === ($length - 1)) {
$i--;
}
}//end if
// Add the skip pattern *after* we have processed
// all the tokens from the end of the last skip pattern
// to the start of this skip pattern.
if ($specialPattern !== false) {
$patterns[] = $specialPattern;
}
}//end for
return $patterns;
}//end _parse()
/**
* Creates a skip pattern.
*
* @param string $pattern The pattern being parsed.
* @param string $from The token content that the skip pattern starts from.
*
* @return array The pattern step.
* @see _createTokenPattern()
* @see _parse()
*/
private function _createSkipPattern($pattern, $from)
{
$skip = array('type' => 'skip');
$nestedParenthesis = 0;
$nestedBraces = 0;
for ($start = $from; $start >= 0; $start--) {
switch ($pattern[$start]) {
case '(':
if ($nestedParenthesis === 0) {
$skip['to'] = 'parenthesis_closer';
}
$nestedParenthesis--;
break;
case '{':
if ($nestedBraces === 0) {
$skip['to'] = 'scope_closer';
}
$nestedBraces--;
break;
case '}':
$nestedBraces++;
break;
case ')':
$nestedParenthesis++;
break;
}//end switch
if (isset($skip['to']) === true) {
break;
}
}//end for
if (isset($skip['to']) === false) {
$skip['to'] = 'unknown';
}
return $skip;
}//end _createSkipPattern()
/**
* Creates a token pattern.
*
* @param string $str The tokens string that the pattern should match.
*
* @return array The pattern step.
* @see _createSkipPattern()
* @see _parse()
*/
private function _createTokenPattern($str)
{
// Don't add a space after the closing php tag as it will add a new
// whitespace token.
$tokenizer = new PHP_CodeSniffer_Tokenizers_PHP();
$tokens = $tokenizer->tokenizeString('<?php '.$str.'?>');
// Remove the <?php tag from the front and the end php tag from the back.
$tokens = array_slice($tokens, 1, (count($tokens) - 2));
$patterns = array();
foreach ($tokens as $patternInfo) {
$patterns[] = array(
'type' => 'token',
'token' => $patternInfo['code'],
'value' => $patternInfo['content'],
);
}
return $patterns;
}//end _createTokenPattern()
}//end class

View File

@@ -0,0 +1,199 @@
<?php
/**
* An AbstractScopeTest allows for tests that extend from this class to
* listen for tokens within a particular scope.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* An AbstractScopeTest allows for tests that extend from this class to
* listen for tokens within a particular scope.
*
* Below is a test that listens to methods that exist only within classes:
* <code>
* class ClassScopeTest extends PHP_CodeSniffer_Standards_AbstractScopeSniff
* {
* public function __construct()
* {
* parent::__construct(array(T_CLASS), array(T_FUNCTION));
* }
*
* protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $)
* {
* $className = $phpcsFile->getDeclarationName($currScope);
* echo 'encountered a method within class '.$className;
* }
* }
* </code>
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
abstract class PHP_CodeSniffer_Standards_AbstractScopeSniff implements PHP_CodeSniffer_Sniff
{
/**
* The token types that this test wishes to listen to within the scope.
*
* @var array
*/
private $_tokens = array();
/**
* The type of scope opener tokens that this test wishes to listen to.
*
* @var string
*/
private $_scopeTokens = array();
/**
* True if this test should fire on tokens outside of the scope.
*
* @var boolean
*/
private $_listenOutside = false;
/**
* Constructs a new AbstractScopeTest.
*
* @param array $scopeTokens The type of scope the test wishes to listen to.
* @param array $tokens The tokens that the test wishes to listen to
* within the scope.
* @param boolean $listenOutside If true this test will also alert the
* extending class when a token is found outside
* the scope, by calling the
* processTokenOutsideScope method.
*
* @see PHP_CodeSniffer.getValidScopeTokeners()
* @throws PHP_CodeSniffer_Exception If the specified tokens array is empty.
*/
public function __construct(
array $scopeTokens,
array $tokens,
$listenOutside=false
) {
if (empty($scopeTokens) === true) {
$error = 'The scope tokens list cannot be empty';
throw new PHP_CodeSniffer_Exception($error);
}
if (empty($tokens) === true) {
$error = 'The tokens list cannot be empty';
throw new PHP_CodeSniffer_Exception($error);
}
$invalidScopeTokens = array_intersect($scopeTokens, $tokens);
if (empty($invalidScopeTokens) === false) {
$invalid = implode(', ', $invalidScopeTokens);
$error = "Scope tokens [$invalid] can't be in the tokens array";
throw new PHP_CodeSniffer_Exception($error);
}
$this->_listenOutside = $listenOutside;
$this->_scopeTokens = array_flip($scopeTokens);
$this->_tokens = $tokens;
}//end __construct()
/**
* The method that is called to register the tokens this test wishes to
* listen to.
*
* DO NOT OVERRIDE THIS METHOD. Use the constructor of this class to register
* for the desired tokens and scope.
*
* @return int[]
* @see __constructor()
*/
public final function register()
{
return $this->_tokens;
}//end register()
/**
* Processes the tokens that this test is listening for.
*
* @param PHP_CodeSniffer_File $phpcsFile The file where this token was found.
* @param int $stackPtr The position in the stack where this
* token was found.
*
* @return void
* @see processTokenWithinScope()
*/
public final function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$foundScope = false;
foreach ($tokens[$stackPtr]['conditions'] as $scope => $code) {
if (isset($this->_scopeTokens[$code]) === true) {
$this->processTokenWithinScope($phpcsFile, $stackPtr, $scope);
$foundScope = true;
}
}
if ($this->_listenOutside === true && $foundScope === false) {
$this->processTokenOutsideScope($phpcsFile, $stackPtr);
}
}//end process()
/**
* Processes a token that is found within the scope that this test is
* listening to.
*
* @param PHP_CodeSniffer_File $phpcsFile The file where this token was found.
* @param int $stackPtr The position in the stack where this
* token was found.
* @param int $currScope The position in the tokens array that
* opened the scope that this test is
* listening for.
*
* @return void
*/
protected abstract function processTokenWithinScope(
PHP_CodeSniffer_File $phpcsFile,
$stackPtr,
$currScope
);
/**
* Processes a token that is found outside the scope that this test is
* listening to.
*
* @param PHP_CodeSniffer_File $phpcsFile The file where this token was found.
* @param int $stackPtr The position in the stack where this
* token was found.
*
* @return void
*/
protected function processTokenOutsideScope(
PHP_CodeSniffer_File $phpcsFile,
$stackPtr
) {
}//end processTokenOutsideScope()
}//end class

View File

@@ -0,0 +1,245 @@
<?php
/**
* A class to find T_VARIABLE tokens.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) {
$error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found';
throw new PHP_CodeSniffer_Exception($error);
}
/**
* A class to find T_VARIABLE tokens.
*
* This class can distinguish between normal T_VARIABLE tokens, and those tokens
* that represent class members. If a class member is encountered, then the
* processMemberVar method is called so the extending class can process it. If
* the token is found to be a normal T_VARIABLE token, then processVariable is
* called.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
abstract class PHP_CodeSniffer_Standards_AbstractVariableSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff
{
/**
* The end token of the current function that we are in.
*
* @var int
*/
private $_endFunction = -1;
/**
* TRUE if a function is currently open.
*
* @var boolean
*/
private $_functionOpen = false;
/**
* The current PHP_CodeSniffer file that we are processing.
*
* @var PHP_CodeSniffer_File
*/
protected $currentFile = null;
/**
* Constructs an AbstractVariableTest.
*/
public function __construct()
{
$scopes = array(
T_CLASS,
T_ANON_CLASS,
T_TRAIT,
T_INTERFACE,
);
$listen = array(
T_FUNCTION,
T_VARIABLE,
T_DOUBLE_QUOTED_STRING,
T_HEREDOC,
);
parent::__construct($scopes, $listen, true);
}//end __construct()
/**
* Processes the token in the specified PHP_CodeSniffer_File.
*
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this
* token was found.
* @param int $stackPtr The position where the token was found.
* @param array $currScope The current scope opener token.
*
* @return void
*/
protected final function processTokenWithinScope(
PHP_CodeSniffer_File $phpcsFile,
$stackPtr,
$currScope
) {
if ($this->currentFile !== $phpcsFile) {
$this->currentFile = $phpcsFile;
$this->_functionOpen = false;
$this->_endFunction = -1;
}
$tokens = $phpcsFile->getTokens();
if ($stackPtr > $this->_endFunction) {
$this->_functionOpen = false;
}
if ($tokens[$stackPtr]['code'] === T_FUNCTION
&& $this->_functionOpen === false
) {
$this->_functionOpen = true;
$methodProps = $phpcsFile->getMethodProperties($stackPtr);
// If the function is abstract, or is in an interface,
// then set the end of the function to it's closing semicolon.
if ($methodProps['is_abstract'] === true
|| $tokens[$currScope]['code'] === T_INTERFACE
) {
$this->_endFunction
= $phpcsFile->findNext(array(T_SEMICOLON), $stackPtr);
} else {
if (isset($tokens[$stackPtr]['scope_closer']) === false) {
$error = 'Possible parse error: non-abstract method defined as abstract';
$phpcsFile->addWarning($error, $stackPtr);
return;
}
$this->_endFunction = $tokens[$stackPtr]['scope_closer'];
}
}//end if
if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING
|| $tokens[$stackPtr]['code'] === T_HEREDOC
) {
// Check to see if this string has a variable in it.
$pattern = '|(?<!\\\\)(?:\\\\{2})*\${?[a-zA-Z0-9_]+}?|';
if (preg_match($pattern, $tokens[$stackPtr]['content']) !== 0) {
$this->processVariableInString($phpcsFile, $stackPtr);
}
return;
}
if ($this->_functionOpen === true) {
if ($tokens[$stackPtr]['code'] === T_VARIABLE) {
$this->processVariable($phpcsFile, $stackPtr);
}
} else {
// What if we assign a member variable to another?
// ie. private $_count = $this->_otherCount + 1;.
$this->processMemberVar($phpcsFile, $stackPtr);
}
}//end processTokenWithinScope()
/**
* Processes the token outside the scope in the file.
*
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this
* token was found.
* @param int $stackPtr The position where the token was found.
*
* @return void
*/
protected final function processTokenOutsideScope(
PHP_CodeSniffer_File $phpcsFile,
$stackPtr
) {
$tokens = $phpcsFile->getTokens();
// These variables are not member vars.
if ($tokens[$stackPtr]['code'] === T_VARIABLE) {
$this->processVariable($phpcsFile, $stackPtr);
} else if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING
|| $tokens[$stackPtr]['code'] === T_HEREDOC
) {
// Check to see if this string has a variable in it.
$pattern = '|(?<!\\\\)(?:\\\\{2})*\${?[a-zA-Z0-9_]+}?|';
if (preg_match($pattern, $tokens[$stackPtr]['content']) !== 0) {
$this->processVariableInString($phpcsFile, $stackPtr);
}
}
}//end processTokenOutsideScope()
/**
* Called to process class member vars.
*
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this
* token was found.
* @param int $stackPtr The position where the token was found.
*
* @return void
*/
abstract protected function processMemberVar(
PHP_CodeSniffer_File $phpcsFile,
$stackPtr
);
/**
* Called to process normal member vars.
*
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this
* token was found.
* @param int $stackPtr The position where the token was found.
*
* @return void
*/
abstract protected function processVariable(
PHP_CodeSniffer_File $phpcsFile,
$stackPtr
);
/**
* Called to process variables found in double quoted strings or heredocs.
*
* Note that there may be more than one variable in the string, which will
* result only in one call for the string or one call per line for heredocs.
*
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this
* token was found.
* @param int $stackPtr The position where the double quoted
* string was found.
*
* @return void
*/
abstract protected function processVariableInString(
PHP_CodeSniffer_File
$phpcsFile,
$stackPtr
);
}//end class

View File

@@ -0,0 +1,27 @@
<documentation title="Duplicate Class Names">
<standard>
<![CDATA[
Class and Interface names should be unique in a project. They should never be duplicated.
]]>
</standard>
<code_comparison>
<code title="Valid: A unique class name.">
<![CDATA[
class <em>Foo</em>
{
}
]]>
</code>
<code title="Invalid: A class duplicated (including across multiple files).">
<![CDATA[
class <em>Foo</em>
{
}
class <em>Foo</em>
{
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,28 @@
<documentation title="Opening Brace on Same Line">
<standard>
<![CDATA[
The opening brace of a class must be on the same line after the definition and must be the last thing on that line.
]]>
</standard>
<code_comparison>
<code title="Valid: Opening brace on the same line.">
<![CDATA[
class Foo <em>{</em>
}
]]>
</code>
<code title="Invalid: Opening brace on the next line.">
<![CDATA[
class Foo
<em>{</em>
}
]]>
</code>
<code title="Invalid: Opening brace not last thing on the line.">
<![CDATA[
class Foo {<em> // Start of class.</em>
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,23 @@
<documentation title="Empty Statements">
<standard>
<![CDATA[
Control Structures must have at least one statement inside of the body.
]]>
</standard>
<code_comparison>
<code title="Valid: There is a statement inside the control structure.">
<![CDATA[
if ($test) {
$var = 1;
}
]]>
</code>
<code title="Invalid: The control structure has no statements.">
<![CDATA[
if ($test) {
<em>// do nothing</em>
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,23 @@
<documentation title="Condition-Only For Loops">
<standard>
<![CDATA[
For loops that have only a second expression (the condition) should be converted to while loops.
]]>
</standard>
<code_comparison>
<code title="Valid: A for loop is used with all three expressions.">
<![CDATA[
for (<em>$i = 0</em>; $i < 10; <em>$i++</em>) {
echo "{$i}\n";
}
]]>
</code>
<code title="Invalid: A for loop is used without a first or third expression.">
<![CDATA[
for (<em></em>;$test;<em></em>) {
$test = doSomething();
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,24 @@
<documentation title="For Loops With Function Calls in the Test">
<standard>
<![CDATA[
For loops should not call functions inside the test for the loop when they can be computed beforehand.
]]>
</standard>
<code_comparison>
<code title="Valid: A for loop that determines its end condition before the loop starts.">
<![CDATA[
<em>$end = count($foo);</em>
for ($i = 0; $i < $end; $i++) {
echo $foo[$i]."\n";
}
]]>
</code>
<code title="Invalid: A for loop that unnecessarily computes the same value on every iteration.">
<![CDATA[
for ($i = 0; $i < <em>count($foo)</em>; $i++) {
echo $foo[$i]."\n";
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,25 @@
<documentation title="Jumbled Incrementers">
<standard>
<![CDATA[
Incrementers in nested loops should use different variable names.
]]>
</standard>
<code_comparison>
<code title="Valid: Two different variables being used to increment.">
<![CDATA[
for ($i = 0; $i < 10; <em>$i++</em>) {
for ($j = 0; $j < 10; <em>$j++</em>) {
}
}
]]>
</code>
<code title="Invalid: Inner incrementer is the same variable name as the outer one.">
<![CDATA[
for ($i = 0; $i < 10; <em>$i++</em>) {
for ($j = 0; $j < 10; <em>$i++</em>) {
}
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,39 @@
<documentation title="Unconditional If Statements">
<standard>
<![CDATA[
If statements that are always evaluated should not be used.
]]>
</standard>
<code_comparison>
<code title="Valid: An if statement that only executes conditionally.">
<![CDATA[
if (<em>$test</em>) {
$var = 1;
}
]]>
</code>
<code title="Invalid: An if statement that is always performed.">
<![CDATA[
if (<em>true</em>) {
$var = 1;
}
]]>
</code>
</code_comparison>
<code_comparison>
<code title="Valid: An if statement that only executes conditionally.">
<![CDATA[
if (<em>$test</em>) {
$var = 1;
}
]]>
</code>
<code title="Invalid: An if statement that is never performed.">
<![CDATA[
if (<em>false</em>) {
$var = 1;
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,29 @@
<documentation title="Unnecessary Final Modifiers">
<standard>
<![CDATA[
Methods should not be declared final inside of classes that are declared final.
]]>
</standard>
<code_comparison>
<code title="Valid: A method in a final class is not marked final.">
<![CDATA[
final class Foo
{
public function bar()
{
}
}
]]>
</code>
<code title="Invalid: A method in a final class is also marked final.">
<![CDATA[
final class Foo
{
public <em>final</em> function bar()
{
}
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,25 @@
<documentation title="Unused function parameters">
<standard>
<![CDATA[
All parameters in a functions signature should be used within the function.
]]>
</standard>
<code_comparison>
<code title="Valid: All the parameters are used.">
<![CDATA[
function addThree($a, $b, $c)
{
return <em>$a + $b + $c</em>;
}
]]>
</code>
<code title="Invalid: One of the parameters is not being used.">
<![CDATA[
function addThree($a, $b, $c)
{
return <em>$a + $b</em>;
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,32 @@
<documentation title="Useless Overriding Methods">
<standard>
<![CDATA[
Methods should not be defined that only call the parent method.
]]>
</standard>
<code_comparison>
<code title="Valid: A method that extends functionality on a parent method.">
<![CDATA[
final class Foo
{
public function bar()
{
parent::bar();
<em>$this->doSomethingElse();</em>
}
}
]]>
</code>
<code title="Invalid: An overriding method that only calls the parent.">
<![CDATA[
final class Foo
{
public function bar()
{
<em>parent::bar();</em>
}
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,25 @@
<documentation title="Todo Comments">
<standard>
<![CDATA[
FIXME Statements should be taken care of.
]]>
</standard>
<code_comparison>
<code title="Valid: A comment without a fixme.">
<![CDATA[
// <em>Handle strange case</em>
if ($test) {
$var = 1;
}
]]>
</code>
<code title="Invalid: A fixme comment.">
<![CDATA[
// <em>FIXME</em>: This needs to be fixed!
if ($test) {
$var = 1;
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,25 @@
<documentation title="Todo Comments">
<standard>
<![CDATA[
TODO Statements should be taken care of.
]]>
</standard>
<code_comparison>
<code title="Valid: A comment without a todo.">
<![CDATA[
// <em>Handle strange case</em>
if ($test) {
$var = 1;
}
]]>
</code>
<code title="Invalid: A todo comment.">
<![CDATA[
// <em>TODO</em>: This needs to be fixed!
if ($test) {
$var = 1;
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,22 @@
<documentation title="Inline Control Structures">
<standard>
<![CDATA[
Control Structures should use braces.
]]>
</standard>
<code_comparison>
<code title="Valid: Braces are used around the control structure.">
<![CDATA[
if ($test) <em>{</em>
$var = 1;
<em>}</em>
]]>
</code>
<code title="Invalid: No braces are used for the control structure..">
<![CDATA[
if ($test)
$var = 1;
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,19 @@
<documentation title="CSSLint">
<standard>
<![CDATA[
All css files should pass the basic csslint tests.
]]>
</standard>
<code_comparison>
<code title="Valid: Valid CSS Syntax is used.">
<![CDATA[
.foo: { width: 100<em></em>%; }
]]>
</code>
<code title="Invalid: The CSS has a typo in it.">
<![CDATA[
.foo: { width: 100<em> </em>%; }
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,19 @@
<documentation title="Closure Linter">
<standard>
<![CDATA[
All javascript files should pass basic Closure Linter tests.
]]>
</standard>
<code_comparison>
<code title="Valid: Valid JS Syntax is used.">
<![CDATA[
var foo = [1, 2<em></em>];
]]>
</code>
<code title="Invalid: Trailing comma in a javascript array.">
<![CDATA[
var foo = [1, 2<em>,</em>];
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,19 @@
<documentation title="JSHint">
<standard>
<![CDATA[
All javascript files should pass basic JSHint tests.
]]>
</standard>
<code_comparison>
<code title="Valid: Valid JS Syntax is used.">
<![CDATA[
<em>var</em> foo = 5;
]]>
</code>
<code title="Invalid: The Javascript is using an undefined variable.">
<![CDATA[
<em></em>foo = 5;
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="Byte Order Marks">
<standard>
<![CDATA[
Byte Order Marks that may corrupt your application should not be used. These include 0xefbbbf (UTF-8), 0xfeff (UTF-16 BE) and 0xfffe (UTF-16 LE).
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="End of File Newline">
<standard>
<![CDATA[
Files should end with a newline character.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="No End of File Newline">
<standard>
<![CDATA[
Files should not end with a newline character.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,24 @@
<documentation title="Inline HTML">
<standard>
<![CDATA[
Files that contain php code should only have php code and should not have any "inline html".
]]>
</standard>
<code_comparison>
<code title="Valid: A php file with only php code in it.">
<![CDATA[
<?php
$foo = 'bar';
echo $foo . 'baz';
]]>
</code>
<code title="Invalid: A php file with html in it outside of the php tags.">
<![CDATA[
<em>some string here</em>
<?php
$foo = 'bar';
echo $foo . 'baz';
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="Line Endings">
<standard>
<![CDATA[
Unix-style line endings are preferred ("\n" instead of "\r\n").
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="Line Length">
<standard>
<![CDATA[
It is recommended to keep lines at approximately 80 characters long for better code readability.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="Lowercased Filenames">
<standard>
<![CDATA[
Lowercase filenames are required.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,29 @@
<documentation title="One Class Per File">
<standard>
<![CDATA[
There should only be one class defined in a file.
]]>
</standard>
<code_comparison>
<code title="Valid: Only one class in the file.">
<![CDATA[
<?php
<em>class Foo</em>
{
}
]]>
</code>
<code title="Invalid: Multiple classes defined in one file.">
<![CDATA[
<?php
<em>class Foo</em>
{
}
<em>class Bar</em>
{
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,29 @@
<documentation title="One Interface Per File">
<standard>
<![CDATA[
There should only be one interface defined in a file.
]]>
</standard>
<code_comparison>
<code title="Valid: Only one interface in the file.">
<![CDATA[
<?php
<em>interface Foo</em>
{
}
]]>
</code>
<code title="Invalid: Multiple interfaces defined in one file.">
<![CDATA[
<?php
<em>interface Foo</em>
{
}
<em>interface Bar</em>
{
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,20 @@
<documentation title="Multiple Statements On a Single Line">
<standard>
<![CDATA[
Multiple statements are not allowed on a single line.
]]>
</standard>
<code_comparison>
<code title="Valid: Two statements are spread out on two separate lines.">
<![CDATA[
$foo = 1;
$bar = 2;
]]>
</code>
<code title="Invalid: Two statements are combined onto one line.">
<![CDATA[
$foo = 1; $bar = 2;
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,56 @@
<documentation title="Aligning Blocks of Assignments">
<standard>
<![CDATA[
There should be one space on either side of an equals sign used to assign a value to a variable. In the case of a block of related assignments, more space may be inserted to promote readability.
]]>
</standard>
<code_comparison>
<code title="Equals signs aligned">
<![CDATA[
$shortVar <em>=</em> (1 + 2);
$veryLongVarName <em>=</em> 'string';
$var <em>=</em> foo($bar, $baz, $quux);
]]>
</code>
<code title="Not aligned; harder to read">
<![CDATA[
$shortVar <em>=</em> (1 + 2);
$veryLongVarName <em>=</em> 'string';
$var <em>=</em> foo($bar, $baz, $quux);
]]>
</code>
</code_comparison>
<standard>
<![CDATA[
When using plus-equals, minus-equals etc. still ensure the equals signs are aligned to one space after the longest variable name.
]]>
</standard>
<code_comparison>
<code title="Equals signs aligned; only one space after longest var name">
<![CDATA[
$shortVar <em>+= </em>1;
$veryLongVarName<em> = </em>1;
]]>
</code>
<code title="Two spaces after longest var name">
<![CDATA[
$shortVar <em> += </em>1;
$veryLongVarName<em> = </em>1;
]]>
</code>
</code_comparison>
<code_comparison>
<code title="Equals signs aligned">
<![CDATA[
$shortVar <em> = </em>1;
$veryLongVarName<em> -= </em>1;
]]>
</code>
<code title="Equals signs not aligned">
<![CDATA[
$shortVar <em> = </em>1;
$veryLongVarName<em> -= </em>1;
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,19 @@
<documentation title="Space After Casts">
<standard>
<![CDATA[
Spaces are not allowed after casting operators.
]]>
</standard>
<code_comparison>
<code title="Valid: A cast operator is immediately before its value.">
<![CDATA[
$foo = (string)1;
]]>
</code>
<code title="Invalid: A cast operator is followed by whitespace.">
<![CDATA[
$foo = (string)<em> </em>1;
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,19 @@
<documentation title="Space After Casts">
<standard>
<![CDATA[
Exactly one space is allowed after a cast.
]]>
</standard>
<code_comparison>
<code title="Valid: A cast operator is followed by one space.">
<![CDATA[
$foo = (string)<em> </em>1;
]]>
</code>
<code title="Invalid: A cast operator is not followed by whitespace.">
<![CDATA[
$foo = (string)<em></em>1;
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,31 @@
<documentation title="Call-Time Pass-By-Reference">
<standard>
<![CDATA[
Call-time pass-by-reference is not allowed. It should be declared in the function definition.
]]>
</standard>
<code_comparison>
<code title="Valid: Pass-by-reference is specified in the function definition.">
<![CDATA[
function foo(<em>&</em>$bar)
{
$bar++;
}
$baz = 1;
foo($baz);
]]>
</code>
<code title="Invalid: Pass-by-reference is done in the call to a function.">
<![CDATA[
function foo($bar)
{
$bar++;
}
$baz = 1;
foo(<em>&</em>$baz);
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,39 @@
<documentation title="Function Argument Spacing">
<standard>
<![CDATA[
Function arguments should have one space after a comma, and single spaces surrounding the equals sign for default values.
]]>
</standard>
<code_comparison>
<code title="Valid: Single spaces after a comma.">
<![CDATA[
function foo($bar,<em> </em>$baz)
{
}
]]>
</code>
<code title="Invalid: No spaces after a comma.">
<![CDATA[
function foo($bar,<em></em>$baz)
{
}
]]>
</code>
</code_comparison>
<code_comparison>
<code title="Valid: Single spaces around an equals sign in function declaration.">
<![CDATA[
function foo($bar, $baz<em> </em>=<em> </em>true)
{
}
]]>
</code>
<code title="Invalid: No spaces around an equals sign in function declaration.">
<![CDATA[
function foo($bar, $baz<em></em>=<em></em>true)
{
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,24 @@
<documentation title="Opening Brace in Function Declarations">
<standard>
<![CDATA[
Function declarations follow the "BSD/Allman style". The function brace is on the line following the function declaration and is indented to the same column as the start of the function declaration.
]]>
</standard>
<code_comparison>
<code title="Valid: brace on next line">
<![CDATA[
function fooFunction($arg1, $arg2 = '')
<em>{</em>
...
}
]]>
</code>
<code title="Invalid: brace on same line">
<![CDATA[
function fooFunction($arg1, $arg2 = '') <em>{</em>
...
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,24 @@
<documentation title="Opening Brace in Function Declarations">
<standard>
<![CDATA[
Function declarations follow the "Kernighan/Ritchie style". The function brace is on the same line as the function declaration. One space is required between the closing parenthesis and the brace.
]]>
</standard>
<code_comparison>
<code title="Valid: brace on same line">
<![CDATA[
function fooFunction($arg1, $arg2 = '')<em> {</em>
...
}
]]>
</code>
<code title="Invalid: brace on next line">
<![CDATA[
function fooFunction($arg1, $arg2 = '')
<em>{</em>
...
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="Cyclomatic Complexity">
<standard>
<![CDATA[
Functions should not have a cyclomatic complexity greater than 20, and should try to stay below a complexity of 10.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="Nesting Level">
<standard>
<![CDATA[
Functions should not have a nesting level greater than 10, and should try to stay below 5.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,23 @@
<documentation title="camelCaps Function Names">
<standard>
<![CDATA[
Functions should use camelCaps format for their names. Only PHP's magic methods should use a double underscore prefix.
]]>
</standard>
<code_comparison>
<code title="Valid: A function in camelCaps format.">
<![CDATA[
function <em>doSomething</em>()
{
}
]]>
</code>
<code title="Invalid: A function in snake_case format.">
<![CDATA[
function <em>do_something</em>()
{
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,29 @@
<documentation title="Constructor name">
<standard>
<![CDATA[
Constructors should be named __construct, not after the class.
]]>
</standard>
<code_comparison>
<code title="Valid: The constructor is named __construct.">
<![CDATA[
class Foo
{
function <em>__construct</em>()
{
}
}
]]>
</code>
<code title="Invalid: The old style class name constructor is used.">
<![CDATA[
class Foo
{
function <em>Foo</em>()
{
}
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,29 @@
<documentation title="Constant Names">
<standard>
<![CDATA[
Constants should always be all-uppercase, with underscores to separate words.
]]>
</standard>
<code_comparison>
<code title="Valid: all uppercase">
<![CDATA[
define('<em>FOO_CONSTANT</em>', 'foo');
class FooClass
{
const <em>FOO_CONSTANT</em> = 'foo';
}
]]>
</code>
<code title="Invalid: mixed case">
<![CDATA[
define('<em>Foo_Constant</em>', 'foo');
class FooClass
{
const <em>foo_constant</em> = 'foo';
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="Backtick Operator">
<standard>
<![CDATA[
Disallow the use of the backtick operator for execution of shell commands.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,22 @@
<documentation title="Opening Tag at Start of File">
<standard>
<![CDATA[
The opening php tag should be the first item in the file.
]]>
</standard>
<code_comparison>
<code title="Valid: A file starting with an opening php tag.">
<![CDATA[
<em></em><?php
echo 'Foo';
]]>
</code>
<code title="Invalid: A file with content before the opening php tag.">
<![CDATA[
<em>Beginning content</em>
<?php
echo 'Foo';
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,22 @@
<documentation title="Closing PHP Tags">
<standard>
<![CDATA[
All opening php tags should have a corresponding closing tag.
]]>
</standard>
<code_comparison>
<code title="Valid: A closing tag paired with it's opening tag.">
<![CDATA[
<em><?php</em>
echo 'Foo';
<em>?></em>
]]>
</code>
<code title="Invalid: No closing tag paired with the opening tag.">
<![CDATA[
<em><?php</em>
echo 'Foo';
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,19 @@
<documentation title="Deprecated Functions">
<standard>
<![CDATA[
Deprecated functions should not be used.
]]>
</standard>
<code_comparison>
<code title="Valid: A non-deprecated function is used.">
<![CDATA[
$foo = <em>explode</em>('a', $bar);
]]>
</code>
<code title="Invalid: A deprecated function is used.">
<![CDATA[
$foo = <em>split</em>('a', $bar);
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="Alternative PHP Code Tags">
<standard>
<![CDATA[
Always use <?php ?> to delimit PHP code, do not use the ASP <% %> style tags nor the <script language="php"></script> tags. This is the most portable way to include PHP code on differing operating systems and setups.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="PHP Code Tags">
<standard>
<![CDATA[
Always use <?php ?> to delimit PHP code, not the <? ?> shorthand. This is the most portable way to include PHP code on differing operating systems and setups.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,19 @@
<documentation title="Forbidden Functions">
<standard>
<![CDATA[
The forbidden functions sizeof() and delete() should not be used.
]]>
</standard>
<code_comparison>
<code title="Valid: count() is used in place of sizeof().">
<![CDATA[
$foo = <em>count</em>($bar);
]]>
</code>
<code title="Invalid: sizeof() is used.">
<![CDATA[
$foo = <em>sizeof</em>($bar);
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,23 @@
<documentation title="PHP Constants">
<standard>
<![CDATA[
The <em>true</em>, <em>false</em> and <em>null</em> constants must always be lowercase.
]]>
</standard>
<code_comparison>
<code title="Valid: lowercase constants">
<![CDATA[
if ($var === <em>false</em> || $var === <em>null</em>) {
$var = <em>true</em>;
}
]]>
</code>
<code title="Invalid: uppercase constants">
<![CDATA[
if ($var === <em>FALSE</em> || $var === <em>NULL</em>) {
$var = <em>TRUE</em>;
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,19 @@
<documentation title="Lowercase Keywords">
<standard>
<![CDATA[
All PHP keywords should be lowercase.
]]>
</standard>
<code_comparison>
<code title="Valid: Lowercase array keyword used.">
<![CDATA[
$foo = <em>array</em>();
]]>
</code>
<code title="Invalid: Non-lowercase array keyword used.">
<![CDATA[
$foo = <em>Array</em>();
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,23 @@
<documentation title="Silenced Errors">
<standard>
<![CDATA[
Suppressing Errors is not allowed.
]]>
</standard>
<code_comparison>
<code title="Valid: isset() is used to verify that a variable exists before trying to use it.">
<![CDATA[
if (<em>isset($foo)</em> && $foo) {
echo "Hello\n";
}
]]>
</code>
<code title="Invalid: Errors are suppressed.">
<![CDATA[
if (<em>@</em>$foo) {
echo "Hello\n";
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,23 @@
<documentation title="SAPI Usage">
<standard>
<![CDATA[
The PHP_SAPI constant should be used instead of php_sapi_name().
]]>
</standard>
<code_comparison>
<code title="Valid: PHP_SAPI is used.">
<![CDATA[
if (<em>PHP_SAPI</em> === 'cli') {
echo "Hello, CLI user.";
}
]]>
</code>
<code title="Invalid: php_sapi_name() is used.">
<![CDATA[
if (<em>php_sapi_name()</em> === 'cli') {
echo "Hello, CLI user.";
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,23 @@
<documentation title="PHP Constants">
<standard>
<![CDATA[
The <em>true</em>, <em>false</em> and <em>null</em> constants must always be uppercase.
]]>
</standard>
<code_comparison>
<code title="Valid: uppercase constants">
<![CDATA[
if ($var === <em>FALSE</em> || $var === <em>NULL</em>) {
$var = <em>TRUE</em>;
}
]]>
</code>
<code title="Invalid: lowercase constants">
<![CDATA[
if ($var === <em>false</em> || $var === <em>null</em>) {
$var = <em>true</em>;
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,19 @@
<documentation title="Unnecessary String Concatenation">
<standard>
<![CDATA[
Strings should not be concatenated together.
]]>
</standard>
<code_comparison>
<code title="Valid: A string can be concatenated with an expression.">
<![CDATA[
echo '5 + 2 = ' . (5 + 2);
]]>
</code>
<code title="Invalid: Strings should not be concatenated together.">
<![CDATA[
echo 'Hello' . ' ' . 'World';
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="Subversion Properties">
<standard>
<![CDATA[
All php files in a subversion repository should have the svn:keywords property set to 'Author Id Revision' and the svn:eol-style property set to 'native'.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="No Space Indentation">
<standard>
<![CDATA[
Tabs should be used for indentation instead of spaces.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,7 @@
<documentation title="No Tab Indentation">
<standard>
<![CDATA[
Spaces should be used for indentation instead of tabs.
]]>
</standard>
</documentation>

View File

@@ -0,0 +1,23 @@
<documentation title="Scope Indentation">
<standard>
<![CDATA[
Indentation for control structures, classes, and functions should be 4 spaces per level.
]]>
</standard>
<code_comparison>
<code title="Valid: 4 spaces are used to indent a control structure.">
<![CDATA[
if ($test) {
<em> </em>$var = 1;
}
]]>
</code>
<code title="Invalid: 8 spaces are used to indent a control structure.">
<![CDATA[
if ($test) {
<em> </em>$var = 1;
}
]]>
</code>
</code_comparison>
</documentation>

View File

@@ -0,0 +1,79 @@
<?php
/**
* Bans the use of the PHP long array syntax.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Bans the use of the PHP long array syntax.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Generic_Sniffs_Arrays_DisallowLongArraySyntaxSniff implements PHP_CodeSniffer_Sniff
{
/**
* Registers the tokens that this sniff wants to listen for.
*
* @return int[]
*/
public function register()
{
return array(T_ARRAY);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$phpcsFile->recordMetric($stackPtr, 'Short array syntax used', 'no');
$error = 'Short array syntax must be used to define arrays';
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'Found');
if ($fix === true) {
$tokens = $phpcsFile->getTokens();
$opener = $tokens[$stackPtr]['parenthesis_opener'];
$closer = $tokens[$stackPtr]['parenthesis_closer'];
$phpcsFile->fixer->beginChangeset();
if ($opener === null) {
$phpcsFile->fixer->replaceToken($stackPtr, '[]');
} else {
$phpcsFile->fixer->replaceToken($stackPtr, '');
$phpcsFile->fixer->replaceToken($opener, '[');
$phpcsFile->fixer->replaceToken($closer, ']');
}
$phpcsFile->fixer->endChangeset();
}
}//end process()
}//end class

View File

@@ -0,0 +1,72 @@
<?php
/**
* Bans the use of the PHP short array syntax.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Bans the use of the PHP short array syntax.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Generic_Sniffs_Arrays_DisallowShortArraySyntaxSniff implements PHP_CodeSniffer_Sniff
{
/**
* Registers the tokens that this sniff wants to listen for.
*
* @return int[]
*/
public function register()
{
return array(T_OPEN_SHORT_ARRAY);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$phpcsFile->recordMetric($stackPtr, 'Short array syntax used', 'yes');
$error = 'Short array syntax is not allowed';
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'Found');
if ($fix === true) {
$tokens = $phpcsFile->getTokens();
$opener = $tokens[$stackPtr]['bracket_opener'];
$closer = $tokens[$stackPtr]['bracket_closer'];
$phpcsFile->fixer->beginChangeset();
$phpcsFile->fixer->replaceToken($opener, 'array(');
$phpcsFile->fixer->replaceToken($closer, ')');
$phpcsFile->fixer->endChangeset();
}
}//end process()
}//end class

View File

@@ -0,0 +1,127 @@
<?php
/**
* Reports errors if the same class or interface name is used in multiple files.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Reports errors if the same class or interface name is used in multiple files.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Generic_Sniffs_Classes_DuplicateClassNameSniff implements PHP_CodeSniffer_Sniff
{
/**
* List of classes that have been found during checking.
*
* @var array
*/
protected $foundClasses = array();
/**
* Registers the tokens that this sniff wants to listen for.
*
* @return int[]
*/
public function register()
{
return array(T_OPEN_TAG);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$namespace = '';
$findTokens = array(
T_CLASS,
T_INTERFACE,
T_NAMESPACE,
T_CLOSE_TAG,
);
$stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1));
while ($stackPtr !== false) {
if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) {
// We can stop here. The sniff will continue from the next open
// tag when PHPCS reaches that token, if there is one.
return;
}
// Keep track of what namespace we are in.
if ($tokens[$stackPtr]['code'] === T_NAMESPACE) {
$nsEnd = $phpcsFile->findNext(
array(
T_NS_SEPARATOR,
T_STRING,
T_WHITESPACE,
),
($stackPtr + 1),
null,
true
);
$namespace = trim($phpcsFile->getTokensAsString(($stackPtr + 1), ($nsEnd - $stackPtr - 1)));
$stackPtr = $nsEnd;
} else {
$nameToken = $phpcsFile->findNext(T_STRING, $stackPtr);
$name = $tokens[$nameToken]['content'];
if ($namespace !== '') {
$name = $namespace.'\\'.$name;
}
$compareName = strtolower($name);
if (isset($this->foundClasses[$compareName]) === true) {
$type = strtolower($tokens[$stackPtr]['content']);
$file = $this->foundClasses[$compareName]['file'];
$line = $this->foundClasses[$compareName]['line'];
$error = 'Duplicate %s name "%s" found; first defined in %s on line %s';
$data = array(
$type,
$name,
$file,
$line,
);
$phpcsFile->addWarning($error, $stackPtr, 'Found', $data);
} else {
$this->foundClasses[$compareName] = array(
'file' => $phpcsFile->getFilename(),
'line' => $tokens[$stackPtr]['line'],
);
}
}//end if
$stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1));
}//end while
}//end process()
}//end class

View File

@@ -0,0 +1,141 @@
<?php
/**
* Generic_Sniffs_Classes_OpeningBraceSameLineSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Generic_Sniffs_Classes_OpeningBraceSameLineSniff.
*
* Checks that the opening brace of a class or interface is on the same line
* as the class declaration.
*
* Also checks that the brace is the last thing on that line and has precisely one space before it.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Generic_Sniffs_Classes_OpeningBraceSameLineSniff implements PHP_CodeSniffer_Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(
T_CLASS,
T_INTERFACE,
T_TRAIT,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token in the
* stack passed in $tokens.
*
* @return void
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$scope_identifier = $phpcsFile->findNext(T_STRING, ($stackPtr + 1));
$errorData = array(strtolower($tokens[$stackPtr]['content']).' '.$tokens[$scope_identifier]['content']);
if (isset($tokens[$stackPtr]['scope_opener']) === false) {
$error = 'Possible parse error: %s missing opening or closing brace';
$phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $errorData);
return;
}
$openingBrace = $tokens[$stackPtr]['scope_opener'];
// Is the brace on the same line as the class/interface/trait declaration ?
$lastClassLineToken = $phpcsFile->findPrevious(T_WHITESPACE, ($openingBrace - 1), $stackPtr, true);
$lastClassLine = $tokens[$lastClassLineToken]['line'];
$braceLine = $tokens[$openingBrace]['line'];
$lineDifference = ($braceLine - $lastClassLine);
if ($lineDifference > 0) {
$phpcsFile->recordMetric($stackPtr, 'Class opening brace placement', 'new line');
$error = 'Opening brace should be on the same line as the declaration for %s';
$fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceOnNewLine', $errorData);
if ($fix === true) {
$phpcsFile->fixer->beginChangeset();
$phpcsFile->fixer->addContent($lastClassLineToken, ' {');
$phpcsFile->fixer->replaceToken($openingBrace, '');
$phpcsFile->fixer->endChangeset();
}
} else {
$phpcsFile->recordMetric($stackPtr, 'Class opening brace placement', 'same line');
}
// Is the opening brace the last thing on the line ?
$next = $phpcsFile->findNext(T_WHITESPACE, ($openingBrace + 1), null, true);
if ($tokens[$next]['line'] === $tokens[$openingBrace]['line']) {
if ($next === $tokens[$stackPtr]['scope_closer']) {
// Ignore empty classes.
return;
}
$error = 'Opening brace must be the last content on the line';
$fix = $phpcsFile->addFixableError($error, $openingBrace, 'ContentAfterBrace');
if ($fix === true) {
$phpcsFile->fixer->addNewline($openingBrace);
}
}
// Only continue checking if the opening brace looks good.
if ($lineDifference > 0) {
return;
}
// Is there precisely one space before the opening brace ?
if ($tokens[($openingBrace - 1)]['code'] !== T_WHITESPACE) {
$length = 0;
} else if ($tokens[($openingBrace - 1)]['content'] === "\t") {
$length = '\t';
} else {
$length = strlen($tokens[($openingBrace - 1)]['content']);
}
if ($length !== 1) {
$error = 'Expected 1 space before opening brace; found %s';
$data = array($length);
$fix = $phpcsFile->addFixableError($error, $openingBrace, 'SpaceBeforeBrace', $data);
if ($fix === true) {
if ($length === 0 || $length === '\t') {
$phpcsFile->fixer->addContentBefore($openingBrace, ' ');
} else {
$phpcsFile->fixer->replaceToken(($openingBrace - 1), ' ');
}
}
}
}//end process()
}//end class

View File

@@ -0,0 +1,108 @@
<?php
/**
* This file is part of the CodeAnalysis add-on for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* This sniff class detected empty statement.
*
* This sniff implements the common algorithm for empty statement body detection.
* A body is considered as empty if it is completely empty or it only contains
* whitespace characters and/or comments.
*
* <code>
* stmt {
* // foo
* }
* stmt (conditions) {
* // foo
* }
* </code>
*
* @category PHP
* @package PHP_CodeSniffer
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Generic_Sniffs_CodeAnalysis_EmptyStatementSniff implements PHP_CodeSniffer_Sniff
{
/**
* Registers the tokens that this sniff wants to listen for.
*
* @return int[]
*/
public function register()
{
return array(
T_TRY,
T_CATCH,
T_FINALLY,
T_DO,
T_ELSE,
T_ELSEIF,
T_FOR,
T_FOREACH,
T_IF,
T_SWITCH,
T_TRY,
T_WHILE,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];
// Skip statements without a body.
if (isset($token['scope_opener']) === false) {
return;
}
$next = $phpcsFile->findNext(
PHP_CodeSniffer_Tokens::$emptyTokens,
($token['scope_opener'] + 1),
($token['scope_closer'] - 1),
true
);
if ($next !== false) {
return;
}
// Get token identifier.
$name = strtoupper($token['content']);
$error = 'Empty %s statement detected';
$phpcsFile->addError($error, $stackPtr, 'Detected'.ucfirst(strtolower($name)), array($name));
}//end process()
}//end class

View File

@@ -0,0 +1,102 @@
<?php
/**
* This file is part of the CodeAnalysis add-on for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Detects for-loops that can be simplified to a while-loop.
*
* This rule is based on the PMD rule catalog. Detects for-loops that can be
* simplified as a while-loop.
*
* <code>
* class Foo
* {
* public function bar($x)
* {
* for (;true;) true; // No Init or Update part, may as well be: while (true)
* }
* }
* </code>
*
* @category PHP
* @package PHP_CodeSniffer
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Generic_Sniffs_CodeAnalysis_ForLoopShouldBeWhileLoopSniff implements PHP_CodeSniffer_Sniff
{
/**
* Registers the tokens that this sniff wants to listen for.
*
* @return int[]
*/
public function register()
{
return array(T_FOR);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];
// Skip invalid statement.
if (isset($token['parenthesis_opener']) === false) {
return;
}
$next = ++$token['parenthesis_opener'];
$end = --$token['parenthesis_closer'];
$parts = array(
0,
0,
0,
);
$index = 0;
for (; $next <= $end; ++$next) {
$code = $tokens[$next]['code'];
if ($code === T_SEMICOLON) {
++$index;
} else if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$code]) === false) {
++$parts[$index];
}
}
if ($parts[0] === 0 && $parts[2] === 0 && $parts[1] > 0) {
$error = 'This FOR loop can be simplified to a WHILE loop';
$phpcsFile->addWarning($error, $stackPtr, 'CanSimplify');
}
}//end process()
}//end class

View File

@@ -0,0 +1,111 @@
<?php
/**
* This file is part of the CodeAnalysis add-on for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Detects for-loops that use a function call in the test expression.
*
* This rule is based on the PMD rule catalog. Detects for-loops that use a
* function call in the test expression.
*
* <code>
* class Foo
* {
* public function bar($x)
* {
* $a = array(1, 2, 3, 4);
* for ($i = 0; $i < count($a); $i++) {
* $a[$i] *= $i;
* }
* }
* }
* </code>
*
* @category PHP
* @package PHP_CodeSniffer
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Generic_Sniffs_CodeAnalysis_ForLoopWithTestFunctionCallSniff implements PHP_CodeSniffer_Sniff
{
/**
* Registers the tokens that this sniff wants to listen for.
*
* @return int[]
*/
public function register()
{
return array(T_FOR);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];
// Skip invalid statement.
if (isset($token['parenthesis_opener']) === false) {
return;
}
$next = ++$token['parenthesis_opener'];
$end = --$token['parenthesis_closer'];
$position = 0;
for (; $next <= $end; ++$next) {
$code = $tokens[$next]['code'];
if ($code === T_SEMICOLON) {
++$position;
}
if ($position < 1) {
continue;
} else if ($position > 1) {
break;
} else if ($code !== T_VARIABLE && $code !== T_STRING) {
continue;
}
// Find next non empty token, if it is a open curly brace we have a
// function call.
$index = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true);
if ($tokens[$index]['code'] === T_OPEN_PARENTHESIS) {
$error = 'Avoid function calls in a FOR loop test part';
$phpcsFile->addWarning($error, $stackPtr, 'NotAllowed');
break;
}
}//end for
}//end process()
}//end class

View File

@@ -0,0 +1,146 @@
<?php
/**
* This file is part of the CodeAnalysis add-on for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Detects incrementer jumbling in for loops.
*
* This rule is based on the PMD rule catalog. The jumbling incrementer sniff
* detects the usage of one and the same incrementer into an outer and an inner
* loop. Even it is intended this is confusing code.
*
* <code>
* class Foo
* {
* public function bar($x)
* {
* for ($i = 0; $i < 10; $i++)
* {
* for ($k = 0; $k < 20; $i++)
* {
* echo 'Hello';
* }
* }
* }
* }
* </code>
*
* @category PHP
* @package PHP_CodeSniffer
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff implements PHP_CodeSniffer_Sniff
{
/**
* Registers the tokens that this sniff wants to listen for.
*
* @return int[]
*/
public function register()
{
return array(T_FOR);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];
// Skip for-loop without body.
if (isset($token['scope_opener']) === false) {
return;
}
// Find incrementors for outer loop.
$outer = $this->findIncrementers($tokens, $token);
// Skip if empty.
if (count($outer) === 0) {
return;
}
// Find nested for loops.
$start = ++$token['scope_opener'];
$end = --$token['scope_closer'];
for (; $start <= $end; ++$start) {
if ($tokens[$start]['code'] !== T_FOR) {
continue;
}
$inner = $this->findIncrementers($tokens, $tokens[$start]);
$diff = array_intersect($outer, $inner);
if (count($diff) !== 0) {
$error = 'Loop incrementor (%s) jumbling with inner loop';
$data = array(join(', ', $diff));
$phpcsFile->addWarning($error, $stackPtr, 'Found', $data);
}
}
}//end process()
/**
* Get all used variables in the incrementer part of a for statement.
*
* @param array(integer=>array) $tokens Array with all code sniffer tokens.
* @param array(string=>mixed) $token Current for loop token
*
* @return string[] List of all found incrementer variables.
*/
protected function findIncrementers(array $tokens, array $token)
{
// Skip invalid statement.
if (isset($token['parenthesis_opener']) === false) {
return array();
}
$start = ++$token['parenthesis_opener'];
$end = --$token['parenthesis_closer'];
$incrementers = array();
$semicolons = 0;
for ($next = $start; $next <= $end; ++$next) {
$code = $tokens[$next]['code'];
if ($code === T_SEMICOLON) {
++$semicolons;
} else if ($semicolons === 2 && $code === T_VARIABLE) {
$incrementers[] = $tokens[$next]['content'];
}
}
return $incrementers;
}//end findIncrementers()
}//end class

View File

@@ -0,0 +1,104 @@
<?php
/**
* This file is part of the CodeAnalysis add-on for PHP_CodeSniffer.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
/**
* Detects unconditional if- and elseif-statements.
*
* This rule is based on the PMD rule catalog. The Unconditional If Statement
* sniff detects statement conditions that are only set to one of the constant
* values <b>true</b> or <b>false</b>
*
* <code>
* class Foo
* {
* public function close()
* {
* if (true)
* {
* // ...
* }
* }
* }
* </code>
*
* @category PHP
* @package PHP_CodeSniffer
* @author Manuel Pichler <mapi@manuel-pichler.de>
* @copyright 2007-2014 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Generic_Sniffs_CodeAnalysis_UnconditionalIfStatementSniff implements PHP_CodeSniffer_Sniff
{
/**
* Registers the tokens that this sniff wants to listen for.
*
* @return int[]
*/
public function register()
{
return array(
T_IF,
T_ELSEIF,
);
}//end register()
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];
// Skip for-loop without body.
if (isset($token['parenthesis_opener']) === false) {
return;
}
$next = ++$token['parenthesis_opener'];
$end = --$token['parenthesis_closer'];
$goodCondition = false;
for (; $next <= $end; ++$next) {
$code = $tokens[$next]['code'];
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$code]) === true) {
continue;
} else if ($code !== T_TRUE && $code !== T_FALSE) {
$goodCondition = true;
}
}
if ($goodCondition === false) {
$error = 'Avoid IF statements that are always true or false';
$phpcsFile->addWarning($error, $stackPtr, 'Found');
}
}//end process()
}//end class

Some files were not shown because too many files have changed in this diff Show More