diff --git a/administrator/components/com_jedchecker/libraries/rules/gpl.ini b/administrator/components/com_jedchecker/libraries/rules/gpl.ini
index 2697061..5056d65 100644
--- a/administrator/components/com_jedchecker/libraries/rules/gpl.ini
+++ b/administrator/components/com_jedchecker/libraries/rules/gpl.ini
@@ -11,4 +11,4 @@
;
; The valid constants to search for
-constants="BSD"
+constants=""
diff --git a/administrator/components/com_jedchecker/libraries/rules/gpl.php b/administrator/components/com_jedchecker/libraries/rules/gpl.php
index cbbe554..c7cf1d8 100644
--- a/administrator/components/com_jedchecker/libraries/rules/gpl.php
+++ b/administrator/components/com_jedchecker/libraries/rules/gpl.php
@@ -13,14 +13,13 @@ defined('_JEXEC') or die('Restricted access');
// Include the rule base class
-require_once(JPATH_COMPONENT_ADMINISTRATOR . '/models/rule.php');
+require_once JPATH_COMPONENT_ADMINISTRATOR . '/models/rule.php';
/**
* class JedcheckerRulesGpl
*
- * This class searches all files for the _JEXEC check
- * which prevents direct file access.
+ * This class searches all files for the GPL/compatible licenses
*
* @since 1.0
*/
@@ -47,6 +46,20 @@ class JedcheckerRulesGpl extends JEDcheckerRule
*/
protected $description = 'COM_JEDCHECKER_RULE_PH1_DESC';
+ /**
+ * Regular expression to match GPL licenses.
+ *
+ * @var string
+ */
+ protected $regexGPLLicenses;
+
+ /**
+ * Regular expression to match GPL-compatible licenses.
+ *
+ * @var string
+ */
+ protected $regexCompatLicenses;
+
/**
* Initiates the file search and check
*
@@ -54,6 +67,9 @@ class JedcheckerRulesGpl extends JEDcheckerRule
*/
public function check()
{
+ // Prepare regexp
+ $this->init();
+
// Find all php files of the extension
$files = JFolder::files($this->basedir, '\.php$', true, true);
@@ -70,7 +86,99 @@ class JedcheckerRulesGpl extends JEDcheckerRule
}
/**
- * Reads a file and searches for the _JEXEC statement
+ * Initialization (prepare regular expressions)
+ *
+ * @return void
+ */
+ protected function init()
+ {
+ $GPLLicenses = (array) file(__DIR__ . '/gpl/gnu.txt');
+ $this->regexGPLLicenses = $this->generateRegexp($GPLLicenses);
+
+ $compatLicenses = (array) file(__DIR__ . '/gpl/compat.txt');
+
+ $extraLicenses = $this->params->get('constants');
+ $extraLicenses = explode(',', $extraLicenses);
+
+ $compatLicenses = array_merge($compatLicenses, $extraLicenses);
+
+ $this->regexCompatLicenses = $this->generateRegexp($compatLicenses);
+ }
+
+ /**
+ * Generate regular expression to match the given list of license names
+ * @param array $lines List of license names
+ *
+ * @return string
+ */
+ protected function generateRegexp($lines)
+ {
+ $titles = array();
+ $ids = array();
+
+ foreach ($lines as $line)
+ {
+ $line = trim($line);
+
+ if ($line === '' || $line[0] === '#')
+ {
+ // Skip empty and commented lines
+ continue;
+ }
+
+ $title = $line;
+ if (substr($line, -1, 1) === ')')
+ {
+ // Extract identifier
+ $pos = strrpos($line, '(');
+
+ if ($pos !== false)
+ {
+ $title = trim(substr($line, 0, $pos));
+
+ $id = trim(substr($line, $pos + 1, -1));
+
+ if ($id !== '')
+ {
+ $id = preg_quote($id, '#');
+ $ids[$id] = 1;
+ }
+ }
+ }
+
+ if ($title !== '')
+ {
+ $title = preg_quote($title, '#');
+
+ // Expand vN.N to different version formats
+ $title = preg_replace('/(?<=\S)\s+v(?=\d)/', ',?\s+(?:v\.?\s*|version\s+)?', $title);
+
+ $title = preg_replace('/\s+/', '\s+', $title);
+
+ $titles[$title] = 1;
+ }
+ }
+
+ if (count($titles) === 0)
+ {
+ return null;
+ }
+
+ $titles = implode('|', array_keys($titles));
+
+ if (count($ids))
+ {
+ $ids = implode('|', array_keys($ids));
+ $titles .=
+ '|\blicense\b.+?(?:' . $ids . ')' .
+ '|\b(?:' . $ids . ')\s+license\b';
+ }
+
+ return '#^.*?(?:' . $titles . ').*?$#im';
+ }
+
+ /**
+ * Reads a file and searches for its license
*
* @param string $file - The path to the file
*
@@ -78,72 +186,46 @@ class JedcheckerRulesGpl extends JEDcheckerRule
*/
protected function find($file)
{
- $content = (array) file($file);
+ $content = php_strip_whitespace($file);
- // Get the constants to look for
- $licenses = $this->params->get('constants');
- $licenses = explode(',', $licenses);
-
- $hascode = 0;
-
- foreach ($content AS $key => $line)
+ // Check the file is empty, comments-only, or nonexecutable
+ if (empty($content) || preg_match('#^<\?php\s+(?:$|(?:die|exit)(?:\(\))?;)#', $content))
{
- $tline = trim($line);
-
- if ($tline == '' || $tline == '')
- {
- continue;
- }
-
- if ($tline['0'] != '/' && $tline['0'] != '*')
- {
- $hascode = 1;
- }
-
- // Search for GPL license
- $gpl = stripos($line, 'GPL');
- $gnu = stripos($line, 'GNU');
- $gpl_long = stripos($line, 'general public license');
-
- if ($gpl || $gnu || $gpl_long)
- {
- $this->report->addInfo(
- $file,
- JText::_('COM_JEDCHECKER_PH1_LICENSE_FOUND') . ':' . '' . $line . '',
- $key
- );
-
- return true;
- }
-
- // Search for the constant name
- foreach ($licenses AS $license)
- {
- $license = trim($license);
-
- // Search for the license
- $found = strpos($line, $license);
-
- // Skip the line if the license is not found
- if ($found === false)
- {
- continue;
- }
- else
- {
- $this->report->addInfo(
- $file,
- JText::_('COM_JEDCHECKER_GPL_COMPATIBLE_LICENSE_WAS_FOUND') . ':' . '' . $line . '',
- $key
- );
-
- return true;
- }
- }
+ return true;
}
- unset($content);
+ // Reload file to preserve comments and line numbers
+ $content = file_get_contents($file);
- return $hascode ? false : true;
+ // Remove leading "*" characters from phpDoc-like comments
+ $content = preg_replace('/^\s*\*/m', '', $content);
+
+ if (preg_match($this->regexGPLLicenses, $content, $match, PREG_OFFSET_CAPTURE))
+ {
+ $lineno = substr_count($content, "\n", 0, $match[0][1]) + 1;
+ $this->report->addInfo(
+ $file,
+ JText::_('COM_JEDCHECKER_PH1_LICENSE_FOUND'),
+ $lineno,
+ $match[0][0]
+ );
+
+ return true;
+ }
+
+ if (preg_match($this->regexCompatLicenses, $content, $match, PREG_OFFSET_CAPTURE))
+ {
+ $lineno = substr_count($content, "\n", 0, $match[0][1]) + 1;
+ $this->report->addWarning(
+ $file,
+ JText::_('COM_JEDCHECKER_GPL_COMPATIBLE_LICENSE_WAS_FOUND'),
+ $lineno,
+ $match[0][0]
+ );
+
+ return true;
+ }
+
+ return false;
}
}
diff --git a/administrator/components/com_jedchecker/libraries/rules/gpl/compat.txt b/administrator/components/com_jedchecker/libraries/rules/gpl/compat.txt
new file mode 100644
index 0000000..add378f
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/gpl/compat.txt
@@ -0,0 +1,81 @@
+# Based on:
+# https://www.gnu.org/licenses/license-list.en.html
+# https://opensource.org/licenses/alphabetical
+# https://spdx.org/licenses/
+
+# Comments are marked with the "#" character in the first position of the line
+
+# Each line contains the full name of the license with the optional abbreviation in parenthesis
+
+# The version of the license (if presented) should be written in the form
+# [space][the letter "v"][digit(s)]
+# (see examples below)
+
+
+# BSD Licenses
+0-clause BSD License (0BSD)
+BSD Zero Clause License
+Zero-Clause BSD / Free Public License v1.0.0
+1-clause BSD License (BSD-1-Clause)
+BSD 1-Clause License
+2-clause BSD License (BSD-2-Clause)
+BSD v2 (BSDv2)
+BSD 2-Clause "Simplified" License
+BSD-2-Clause Plus Patent License (BSD-2-Clause-Patent)
+FreeBSD License
+3-clause BSD License (BSD-3-Clause)
+BSD v3 (BSDv3)
+BSD 3-Clause "New" or "Revised" License
+Modified BSD License
+Clear BSD License
+
+# Other GPL-compatible Licenses
+Apache License v2.0 (Apache-2.0)
+Artistic License v2.0 (Artistic-2.0)
+Berkeley Database License
+Boost Software License (BSL-1.0)
+CeCILL v2
+CeCILL License v2.1 (CECILL-2.1)
+CeCILL Free Software License Agreement v2.1
+Clarified Artistic License
+Cryptix General License
+eCos License v2.0 (eCos-2.0)
+Educational Community License v2.0 (ECL-2.0)
+Eiffel Forum License v2.0 (EFL-2.0)
+EU DataGrid Software License (EUDatagrid)
+Expat License
+Freetype Project License
+Historical Permission Notice and Disclaimer (HPND)
+Independent JPEG Group License
+Intel Open Source License (Intel)
+ISC License (ISC)
+MIT License (MIT)
+Mozilla Public License v2.0 (MPL-2.0)
+OpenLDAP License v2.7
+OpenLDAP Public License v2.8 (OLDAP-2.8)
+Open LDAP Public License v2.8
+Public Domain
+Python License (Python-2.0)
+SGI Free Software License B v2.0
+Sleepycat License (Sleepycat)
+Sleepycat Software Product License
+Standard ML of New Jersey Copyright License
+Unicode Data Files and Software License (Unicode-DFS-2016)
+Unicode License Agreement - Data Files and Software
+Unicode, Inc. License Agreement for Data Files and Software
+Universal Permissive License (UPL)
+Universal Permissive License v1.0 (UPL-1.0)
+University of Illinois/NCSA Open Source License (NCSA)
+NCSA/University of Illinois Open Source License
+Unlicense
+W3C License
+W3C Software Notice and License
+WTFPL v2
+WxWidgets Library License
+wxWindows Library License (WXwindows)
+X11 License
+XFree86 v1.1 License
+Zope Public License v2.0 (ZPL-2.0)
+Zope Public License v2.1
+zlib/libpng License (Zlib)
+zlib License
diff --git a/administrator/components/com_jedchecker/libraries/rules/gpl/gnu.txt b/administrator/components/com_jedchecker/libraries/rules/gpl/gnu.txt
new file mode 100644
index 0000000..8e2979f
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/gpl/gnu.txt
@@ -0,0 +1,38 @@
+# GPL Licenses
+
+# Based on:
+# https://www.gnu.org/licenses/license-list.en.html
+# https://opensource.org/licenses/alphabetical
+# https://spdx.org/licenses/
+
+# Comments are marked with the "#" character in the first position of the line
+
+# Each line contains the full name of the license with the optional abbreviation in parenthesis
+
+# The version of the license (if presented) should be written in the form
+# [space][the letter "v"][digit(s)]
+# (see examples below)
+
+
+GNU General Public License
+GNU GPL
+GNU/GPL
+GNU Lesser General Public License
+GNU LGPL
+GNU/LGPL
+
+GNU General Public License v2 (GPL-2.0)
+//www.gnu.org/licenses/gpl-2.0.html
+
+GNU General Public License v3 (GPL-3.0)
+//www.gnu.org/licenses/gpl-3.0.html
+
+GNU Affero General Public License v3 (AGPL-3.0)
+GNU Affero General Public License (AGPL) v3
+GNU Library General Public License v2 (LGPL-2.0)
+GNU Lesser General Public License v2.1 (LGPL-2.1)
+GNU Lesser General Public License (LGPL) v2.1
+GNU Lesser General Public License v3 (LGPL-3.0)
+GNU Lesser General Public License (LGPL) v3
+
+GNU All-Permissive License