From 0a09a14fb3e0e39b7fdeb6c53aff50ff0dc34105 Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Tue, 23 Feb 2021 22:20:25 +0300 Subject: [PATCH 01/10] don't search for JEXEC guard in comments --- .../com_jedchecker/libraries/rules/jexec.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.php b/administrator/components/com_jedchecker/libraries/rules/jexec.php index 8a5ca59..b3d5c29 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.php +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.php @@ -77,7 +77,16 @@ class JedcheckerRulesJexec extends JEDcheckerRule */ protected function find($file) { - $content = (array) file($file); + // load file and strip comments + $content = php_strip_whitespace($file); + + // skip empty files + if ($content === '' || preg_match('#^<\?php\s+$#', $content)) + { + return true; + } + + $content = preg_split('/(?:\r\n|\n|\r)(?!$)/', $content); // Get the constants to look for $defines = $this->params->get('constants'); From 1a201318c6590137b24d5543f68be9007550e4f4 Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Tue, 23 Feb 2021 22:22:29 +0300 Subject: [PATCH 02/10] use a single regex match in the jexec rule --- .../com_jedchecker/libraries/rules/jexec.php | 100 ++++++------------ 1 file changed, 33 insertions(+), 67 deletions(-) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.php b/administrator/components/com_jedchecker/libraries/rules/jexec.php index b3d5c29..34aba0a 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.php +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.php @@ -46,6 +46,13 @@ class JedcheckerRulesJexec extends JEDcheckerRule */ protected $description = 'COM_JEDCHECKER_RULE_PH2_DESC'; + /** + * Regexp to match _JEXEC-like guard + * + * @var string + */ + protected $regex; + /** * Initiates the file search and check * @@ -53,6 +60,8 @@ class JedcheckerRulesJexec extends JEDcheckerRule */ public function check() { + $this->init_jexec(); + // Find all php files of the extension $files = JFolder::files($this->basedir, '\.php$', true, true); @@ -86,79 +95,36 @@ class JedcheckerRulesJexec extends JEDcheckerRule return true; } - $content = preg_split('/(?:\r\n|\n|\r)(?!$)/', $content); + // check guards + if (preg_match($this->regex, $content)) + { + return true; + } - // Get the constants to look for + return false; + } + + /** + * Prepare regexp aforehand + * + * @return void + */ + protected function init_jexec() + { $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 == '') - { - 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); - - return $hascode ? false : true; + $this->regex + = '#^' // at the beginning of the file + . '<\?php\s+' // there is an opening php tag + . 'defined ?\( ?' // followed by defined test + . '([\'"])(?:' . implode('|', $defines) . ')\1' // of any of given constant + . ' ?\) ?(?:or |\|\| ?)(?:die|exit)\b' // or exit + . '#i'; // (case insensitive) } } From edf06dc1353b50f105ad183d471f9bd8e058986b Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Tue, 9 Mar 2021 23:39:05 +0300 Subject: [PATCH 03/10] Allow declare/namespace/use statements before the JEXEC guard --- .../components/com_jedchecker/libraries/rules/jexec.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.php b/administrator/components/com_jedchecker/libraries/rules/jexec.php index 34aba0a..25bbfc8 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.php +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.php @@ -122,6 +122,9 @@ class JedcheckerRulesJexec extends JEDcheckerRule $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 From 58e3bebf6774736467549a9ea1965f8c272857ed Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Tue, 9 Mar 2021 23:41:06 +0300 Subject: [PATCH 04/10] Auto-detect external library directories --- .../com_jedchecker/libraries/rules/jexec.ini | 2 + .../com_jedchecker/libraries/rules/jexec.php | 82 ++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.ini b/administrator/components/com_jedchecker/libraries/rules/jexec.ini index 869f855..f0d0401 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.ini +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.ini @@ -12,3 +12,5 @@ ; The valid constants to search for constants ="_JEXEC, JPATH_PLATFORM, JPATH_BASE, AKEEBAENGINE, WF_EDITOR" +libfolders="vendor,composer" +libfiles="LICENSE,LICENSE.txt,license.txt,dcomposer.json" diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.php b/administrator/components/com_jedchecker/libraries/rules/jexec.php index 25bbfc8..d82b3db 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.php +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.php @@ -53,6 +53,20 @@ class JedcheckerRulesJexec extends JEDcheckerRule */ 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 * @@ -63,7 +77,7 @@ class JedcheckerRulesJexec extends JEDcheckerRule $this->init_jexec(); // 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) @@ -129,5 +143,71 @@ class JedcheckerRulesJexec extends JEDcheckerRule . '([\'"])(?:' . implode('|', $defines) . ')\1' // of any of given constant . ' ?\) ?(?:or |\|\| ?)(?:die|exit)\b' // or exit . '#i'; // (case insensitive) + + // 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) + { + $path = JPath::clean($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; } } From 9e2c702b6bcaf25700538c8151af794a8f81b7bc Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Sun, 4 Apr 2021 15:00:40 +0300 Subject: [PATCH 05/10] add a comment --- .../components/com_jedchecker/libraries/rules/jexec.php | 1 + 1 file changed, 1 insertion(+) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.php b/administrator/components/com_jedchecker/libraries/rules/jexec.php index d82b3db..26c9a0a 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.php +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.php @@ -125,6 +125,7 @@ class JedcheckerRulesJexec extends JEDcheckerRule */ protected function init_jexec() { + // Generate regular expression to match JEXEC quard $defines = $this->params->get('constants'); $defines = explode(',', $defines); From 37e563b14b927abb618a7b81d64f76fb270e22af Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Sun, 4 Apr 2021 15:06:48 +0300 Subject: [PATCH 06/10] fix Joomla codestyle --- .../com_jedchecker/libraries/rules/jexec.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.php b/administrator/components/com_jedchecker/libraries/rules/jexec.php index 26c9a0a..0dad7bb 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.php +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.php @@ -74,7 +74,7 @@ class JedcheckerRulesJexec extends JEDcheckerRule */ public function check() { - $this->init_jexec(); + $this->initJexec(); // Find all php files of the extension $files = $this->files($this->basedir); @@ -100,16 +100,16 @@ class JedcheckerRulesJexec extends JEDcheckerRule */ protected function find($file) { - // load file and strip comments + // Load file and strip comments $content = php_strip_whitespace($file); - // skip empty files + // Skip empty files if ($content === '' || preg_match('#^<\?php\s+$#', $content)) { return true; } - // check guards + // Check guards if (preg_match($this->regex, $content)) { return true; @@ -119,11 +119,11 @@ class JedcheckerRulesJexec extends JEDcheckerRule } /** - * Prepare regexp aforehand + * Prepare regexps aforehand * * @return void */ - protected function init_jexec() + protected function initJexec() { // Generate regular expression to match JEXEC quard $defines = $this->params->get('constants'); From 56363f5a098e3c4b8df0b9c339749710af43038e Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Sun, 4 Apr 2021 17:11:05 +0300 Subject: [PATCH 07/10] fix typo in composer.json --- .../components/com_jedchecker/libraries/rules/jexec.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.ini b/administrator/components/com_jedchecker/libraries/rules/jexec.ini index f0d0401..d58d0f1 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.ini +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.ini @@ -13,4 +13,4 @@ ; The valid constants to search for constants ="_JEXEC, JPATH_PLATFORM, JPATH_BASE, AKEEBAENGINE, WF_EDITOR" libfolders="vendor,composer" -libfiles="LICENSE,LICENSE.txt,license.txt,dcomposer.json" +libfiles="LICENSE,LICENSE.txt,license.txt,composer.json" From f6df5dc520fdaf0fe6e1c8cb3f8fa212545d95e4 Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Tue, 11 May 2021 14:41:11 +0300 Subject: [PATCH 08/10] Fix backslash in paths on Windows --- .../components/com_jedchecker/libraries/rules/jexec.php | 1 - 1 file changed, 1 deletion(-) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.php b/administrator/components/com_jedchecker/libraries/rules/jexec.php index 0dad7bb..9677645 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.php +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.php @@ -172,7 +172,6 @@ class JedcheckerRulesJexec extends JEDcheckerRule */ protected function files($path) { - $path = JPath::clean($path); $arr = array(); // Read the source directory From 266ab63780b77ad412b87f2fd68d0049b536fb79 Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Mon, 17 May 2021 20:04:37 +0300 Subject: [PATCH 09/10] clean BOM before JEXEC check --- .../components/com_jedchecker/libraries/rules/jexec.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.php b/administrator/components/com_jedchecker/libraries/rules/jexec.php index 9677645..520ed1e 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.php +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.php @@ -103,6 +103,9 @@ class JedcheckerRulesJexec extends JEDcheckerRule // Load file and strip comments $content = php_strip_whitespace($file); + // Strip BOM (it is checked separately) + $content = preg_replace('/^\xEF\xBB\xBF/', '', $content); + // Skip empty files if ($content === '' || preg_match('#^<\?php\s+$#', $content)) { From 5dd80910863169f1c7fe81500e99e330199629e7 Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Tue, 31 Aug 2021 21:59:45 +0300 Subject: [PATCH 10/10] add vendors and libraries to the libfolders list --- .../components/com_jedchecker/libraries/rules/jexec.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_jedchecker/libraries/rules/jexec.ini b/administrator/components/com_jedchecker/libraries/rules/jexec.ini index d58d0f1..b632900 100644 --- a/administrator/components/com_jedchecker/libraries/rules/jexec.ini +++ b/administrator/components/com_jedchecker/libraries/rules/jexec.ini @@ -12,5 +12,5 @@ ; The valid constants to search for constants ="_JEXEC, JPATH_PLATFORM, JPATH_BASE, AKEEBAENGINE, WF_EDITOR" -libfolders="vendor,composer" +libfolders="vendor,vendors,composer,libraries" libfiles="LICENSE,LICENSE.txt,license.txt,composer.json"