31
2
mirror of https://github.com/joomla-extensions/jedchecker.git synced 2024-06-05 06:50:47 +00:00

Merge PR #108 into develop

This commit is contained in:
Llewellyn van der Merwe 2021-09-01 10:13:19 +02:00
commit f37763ecc9
Signed by: Llewellyn
GPG Key ID: EFC0C720A240551C
2 changed files with 130 additions and 67 deletions

View File

@ -12,3 +12,5 @@
; The valid constants to search for
constants ="_JEXEC, JPATH_PLATFORM, JPATH_BASE, AKEEBAENGINE, WF_EDITOR"
libfolders="vendor,vendors,composer,libraries"
libfiles="LICENSE,LICENSE.txt,license.txt,composer.json"

View File

@ -53,6 +53,27 @@ class JedcheckerRulesJexec extends JEDcheckerRule
*/
public static $ordering = 600;
/**
* Regexp to match _JEXEC-like guard
*
* @var string
*/
protected $regex;
/**
* Regexp to match directories to skip
*
* @var string
*/
protected $regexExcludeFolders;
/**
* List of files related to libraries
*
* @var array
*/
protected $libFiles;
/**
* Initiates the file search and check
*
@ -60,8 +81,10 @@ class JedcheckerRulesJexec extends JEDcheckerRule
*/
public function check()
{
$this->initJexec();
// Find all php files of the extension
$files = JFolder::files($this->basedir, '\.php$', true, true);
$files = $this->files($this->basedir);
// Iterate through all files
foreach ($files as $file)
@ -84,79 +107,117 @@ class JedcheckerRulesJexec extends JEDcheckerRule
*/
protected function find($file)
{
$content = (array) file($file);
// Load file and strip comments
$content = php_strip_whitespace($file);
// Get the constants to look for
// Strip BOM (it is checked separately)
$content = preg_replace('/^\xEF\xBB\xBF/', '', $content);
// Skip empty files
if ($content === '' || preg_match('#^<\?php\s+$#', $content))
{
return true;
}
// Check guards
if (preg_match($this->regex, $content))
{
return true;
}
return false;
}
/**
* Prepare regexps aforehand
*
* @return void
*/
protected function initJexec()
{
// Generate regular expression to match JEXEC quard
$defines = $this->params->get('constants');
$defines = explode(',', $defines);
$hascode = 0;
foreach ($content AS $line)
foreach ($defines as $i => $define)
{
$tline = trim($line);
if ($tline == '' || $tline == '<?php' || $tline == '?>')
{
continue;
}
if ($tline['0'] != '/' && $tline['0'] != '*')
{
$hascode = 1;
}
// Search for "defined"
$pos_1 = stripos($line, 'defined');
// Skip the line if "defined" is not found
if ($pos_1 === false)
{
continue;
}
// Search for "die".
// "or" may not be present depending on syntax
$pos_3 = stripos($line, 'die');
// Check for "exit"
if ($pos_3 === false)
{
$pos_3 = stripos($line, 'exit');
// Skip the line if "die" or "exit" is not found
if ($pos_3 === false)
{
continue;
}
}
// Search for the constant name
foreach ($defines AS $define)
{
$define = trim($define);
// Search for the define
$pos_2 = strpos($line, $define);
// Skip the line if the define is not found
if ($pos_2 === false)
{
continue;
}
// Check the position of the words
if ($pos_2 > $pos_1 && $pos_3 > $pos_2)
{
unset($content);
return true;
}
}
$defines[$i] = preg_quote(trim($define), '#');
}
unset($content);
$this->regex
= '#^' // at the beginning of the file
. '<\?php\s+' // there is an opening php tag
. '(?:declare ?\(strict_types ?= ?1 ?\) ?; ?)?' // optionally followed by declare(strict_types=1) directive
. '(?:namespace [0-9A-Za-z_\\\\]+ ?; ?)?' // optionally followed by namespace directive
. '(?:use [0-9A-Za-z_\\\\]+ ?(?:as [0-9A-Za-z_]+ ?)?; ?)*' // optionally followed by use directives
. 'defined ?\( ?' // followed by defined test
. '([\'"])(?:' . implode('|', $defines) . ')\1' // of any of given constant
. ' ?\) ?(?:or |\|\| ?)(?:die|exit)\b' // or exit
. '#i'; // (case insensitive)
return $hascode ? false : true;
// Generate regular expression to match excluded directories
$libfolders = $this->params->get('libfolders');
$libfolders = explode(',', $libfolders);
foreach ($libfolders as &$libfolder)
{
$libfolder = preg_quote(trim($libfolder), '#');
}
// Prepend libFolders with default Joomla's exclude list
$this->regexExcludeFolders = '#^(?:\.svn|CVS|\.DS_Store|__MACOSX|' . implode('|', $libfolders) . ')$#';
// Generate list of libraries fingerprint files
$libFiles = $this->params->get('libfiles');
$this->libFiles = array_map('trim', explode(',', $libFiles));
}
/**
* Collect php files to check (excluding external library directories)
*
* @param string $path The path of the folder to read.
*
* @return array
* @since 3.0
*/
protected function files($path)
{
$arr = array();
// Read the source directory
if ($handle = @opendir($path))
{
while (($file = readdir($handle)) !== false)
{
// Skip excluded directories
if ($file !== '.' && $file !== '..' && !preg_match($this->regexExcludeFolders, $file))
{
$fullpath = $path . '/' . $file;
if (is_dir($fullpath))
{
// Detect and skip external library directories
foreach ($this->libFiles as $libFile)
{
if (is_file($fullpath . '/' . $libFile))
{
// Skip processing of this directory
continue 2;
}
}
$arr = array_merge($arr, $this->files($fullpath));
}
elseif (preg_match('/\.php$/', $file))
{
$arr[] = $fullpath;
}
}
}
closedir($handle);
}
return $arr;
}
}