mirror of
https://github.com/joomla-extensions/jedchecker.git
synced 2024-12-01 01:03:55 +00:00
clean PHP code (by removing comments, html, and strings) in the framework rules to avoid false-positives
This commit is contained in:
parent
21faa210dc
commit
fb16f918d3
@ -104,12 +104,14 @@ class JedcheckerRulesFramework extends JEDcheckerRule
|
||||
*/
|
||||
protected function find($file)
|
||||
{
|
||||
$content = (array) file($file);
|
||||
$origContent = (array) file($file);
|
||||
$cleanContent = preg_split("/(?:\r\n|\n|\r)(?!$)/", $this->cleanNonCode($file));
|
||||
|
||||
$result = false;
|
||||
|
||||
foreach ($this->getTests() as $testObject)
|
||||
{
|
||||
if ($this->runTest($file, $content, $testObject))
|
||||
if ($this->runTest($file, $origContent, $cleanContent, $testObject))
|
||||
{
|
||||
$result = true;
|
||||
}
|
||||
@ -118,35 +120,146 @@ class JedcheckerRulesFramework extends JEDcheckerRule
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function cleanNonCode($file)
|
||||
{
|
||||
$content = file_get_contents($file);
|
||||
|
||||
if (!preg_match('/<\?php\s/i', $content, $match, PREG_OFFSET_CAPTURE))
|
||||
{
|
||||
// No PHP code found
|
||||
return '';
|
||||
}
|
||||
|
||||
$pos = $match[0][1];
|
||||
$cleanContent = $this->removeContent(substr($content, 0, $pos));
|
||||
|
||||
while (preg_match('/(?:[\'"]|\/\*|\/\/|\?>)/', $content, $match, PREG_OFFSET_CAPTURE, $pos))
|
||||
{
|
||||
$foundPos = $match[0][1];
|
||||
$cleanContent .= substr($content, $pos, $foundPos - $pos);
|
||||
$pos = $foundPos;
|
||||
|
||||
switch ($match[0][0])
|
||||
{
|
||||
case '"':
|
||||
case "'":
|
||||
$q = $match[0][0];
|
||||
|
||||
if (!preg_match("/$q(?>[^$q\\\\]+|\\\\.)*$q/As", $content, $match, 0, $pos))
|
||||
{
|
||||
return $cleanContent . $q;
|
||||
}
|
||||
|
||||
$cleanContent .= $q . $this->removeContent($match[0]) . $q;
|
||||
$pos += strlen($match[0]);
|
||||
break;
|
||||
|
||||
case '/*':
|
||||
$cleanContent .= '/*';
|
||||
$pos += 2;
|
||||
|
||||
$endPos = strpos($content, '*/', $pos);
|
||||
|
||||
if ($endPos === false)
|
||||
{
|
||||
return $cleanContent;
|
||||
}
|
||||
|
||||
$cleanContent .= $this->removeContent(substr($content, $pos, $endPos - $pos)) . '*/';
|
||||
$pos = $endPos + 2;
|
||||
|
||||
break;
|
||||
|
||||
case '//':
|
||||
$pos += strcspn($content, "\r\n", $pos);
|
||||
break;
|
||||
|
||||
case '?>':
|
||||
$cleanContent .= '?>';
|
||||
$pos += 2;
|
||||
|
||||
if (!preg_match('/<\?php\s/i', $content, $match, PREG_OFFSET_CAPTURE, $pos))
|
||||
{
|
||||
// No PHP code found (up to the end of the file)
|
||||
return $cleanContent;
|
||||
}
|
||||
|
||||
$foundPos = $match[0][1];
|
||||
$cleanContent .= $this->removeContent(substr($content, $pos, $foundPos - $pos)) . $match[0][0];
|
||||
$pos = $foundPos + strlen($match[0][0]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $cleanContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all text content by keeping newline characters only
|
||||
*
|
||||
* @param string $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function removeContent($content)
|
||||
{
|
||||
return str_repeat("\n", substr_count($content, "\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
* runs tests and reports to the appropriate function if strings match.
|
||||
*
|
||||
* @param string $file The file name
|
||||
* @param array $content The file content
|
||||
* @param array $origContent The file content
|
||||
* @param array $cleanContent The file content w/o non-code elements
|
||||
* @param object $testObject The test object generated by getTests()
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function runTest($file, $content, $testObject)
|
||||
private function runTest($file, $origContent, $cleanContent, $testObject)
|
||||
{
|
||||
// @todo remove as unused?
|
||||
$error_count = 0;
|
||||
|
||||
foreach ($content as $line_number => $line)
|
||||
foreach ($cleanContent as $line_number => $line)
|
||||
{
|
||||
$origLine = $origContent[$line_number];
|
||||
|
||||
foreach ($testObject->tests AS $singleTest)
|
||||
{
|
||||
if (stripos($line, $singleTest) !== false)
|
||||
$regex = preg_quote($singleTest, '/');
|
||||
|
||||
if (ctype_alpha($singleTest[0]))
|
||||
{
|
||||
$line = str_ireplace($singleTest, '<b>' . $singleTest . '</b>', $line);
|
||||
$error_message = JText::_('COM_JEDCHECKER_ERROR_FRAMEWORK_' . strtoupper($testObject->group)) . ':<pre>' . $line . '</pre>';
|
||||
$regex = '(?<=\W|^)' . $regex;
|
||||
}
|
||||
|
||||
if (ctype_alpha($singleTest[strlen($singleTest) - 1]))
|
||||
{
|
||||
$regex .= '(?=\W|$)';
|
||||
}
|
||||
|
||||
if (preg_match('/' . $regex . '/i', $line))
|
||||
{
|
||||
$origLine = str_ireplace($singleTest, '<b>' . $singleTest . '</b>', htmlspecialchars($origLine));
|
||||
$error_message = JText::_('COM_JEDCHECKER_ERROR_FRAMEWORK_' . strtoupper($testObject->group)) . ':<pre>' . $origLine . '</pre>';
|
||||
|
||||
switch ($testObject->kind)
|
||||
{
|
||||
case 'error':$this->report->addError($file, $error_message, $line_number);
|
||||
case 'error':
|
||||
$this->report->addError($file, $error_message, $line_number);
|
||||
break;
|
||||
case 'warning':$this->report->addWarning($file, $error_message, $line_number);
|
||||
case 'warning':
|
||||
$this->report->addWarning($file, $error_message, $line_number);
|
||||
break;
|
||||
case 'compatibility':$this->report->addCompat($file, $error_message, $line_number);
|
||||
case 'compatibility':
|
||||
$this->report->addCompat($file, $error_message, $line_number);
|
||||
break;
|
||||
default:
|
||||
// Case 'notice':
|
||||
@ -154,6 +267,7 @@ class JedcheckerRulesFramework extends JEDcheckerRule
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If you scored 10 errors on a single file, that's enough for now.
|
||||
if ($error_count > 10)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user