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

Merge PR #80 with develop

This commit is contained in:
Llewellyn van der Merwe 2021-04-27 00:59:38 +02:00
commit 5ee979715d
Signed by: Llewellyn
GPG Key ID: EFC0C720A240551C
2 changed files with 237 additions and 26 deletions

View File

@ -40,9 +40,19 @@ COM_JEDCHECKER_LEAVE_A_REVIEW_JED="If you use this component, please post a rati
COM_JEDCHECKER_INFO="Info"
COM_JEDCHECKER_INFO_XML="Information about extension xml files"
COM_JEDCHECKER_INFO_XML_DESC="The install name of your extension must match your listing name on JED. We scan the xml files and find the value of the name tag. Useful information for the "filename and install as" fields in the jed submission form"
COM_JEDCHECKER_INFO_XML_MANIFEST_OUTDATED="Manifest file uses outdated format. Use <extension> instead of <install> root tag name."
COM_JEDCHECKER_INFO_XML_NAME_XML="The name tag in this file is: <b>%s</b>"
COM_JEDCHECKER_INFO_XML_VERSION_XML="Version tag has the value: %s"
COM_JEDCHECKER_INFO_XML_CREATIONDATE_XML="The creationDate tag has the value: %s"
COM_JEDCHECKER_INFO_XML_NO_MANIFEST="No manifest file found"
COM_JEDCHECKER_INFO_XML_NAME_MODULE_PLUGIN="Listing name ('%s') contains 'module' or 'plugin'"
COM_JEDCHECKER_INFO_XML_NAME_RESERVED_KEYWORDS="Keywords such as module, plugin or template are considered reserved words and can't be used in the extension names ('%s')"
COM_JEDCHECKER_INFO_XML_NAME_VERSION="Version in name/title ('%s')"
COM_JEDCHECKER_INFO_XML_NAME_JOOMLA="An extension name ('%s') can't start with the word 'Joomla'"
COM_JEDCHECKER_INFO_XML_NAME_JOOMLA_DERIVATIVE="Extensions that use 'Joomla' or a derivative of Joomla in the extension name ('%s') need to be licensed by OSM"
COM_JEDCHECKER_INFO_XML_URL_JOOMLA_DERIVATIVE="Domain names that use 'Joomla' or a derivative of Joomla ('%1$s') need to be licensed by OSM. Please, check your domain name is listed on the <a href='%2$s'>Joomla! Trademark Approval Registry</a> page."
COM_JEDCHECKER_INFO_XML_NAME_ADMIN_MENU="The admin menu name '%1$s' isn't the same as the extension name '%2$s'"
COM_JEDCHECKER_INFO_XML_NAME_PLUGIN_FORMAT="The name of the plugin ('%s') must comply with the JED naming conventions in the form '{Type} - {Extension Name}'"
COM_JEDCHECKER_RULE_PH1="PHP Headers missing GPL License Notice"
COM_JEDCHECKER_RULE_PH1_DESC="A notice is required on each PHP file stating that the file is licensed GPL (or other compatible accepted license). For more information, please <a href='http://extensions.joomla.org/support/knowledgebase/item/jed-entries-checklists#licensechecklist' target='_blank'>click here</a>."
COM_JEDCHECKER_ERROR_GPL_NOT_FOUND="GPL or compatible license was not found"

View File

@ -20,7 +20,7 @@ require_once JPATH_COMPONENT_ADMINISTRATOR . '/models/rule.php';
/**
* class JedcheckerRulesXMLinfo
*
* This class searches all xml manifestes for specific tags
* This class searches all xml manifests for specific tags
*
* @since 1.0
*/
@ -47,6 +47,18 @@ class JedcheckerRulesXMLinfo extends JEDcheckerRule
*/
protected $description = 'COM_JEDCHECKER_INFO_XML_DESC';
/**
* Mapping of the plugin title prefix to the plugin group
*
* @var string[]
*/
protected $pluginsGroupMap = array(
'button' => 'editors-xtd',
'editor' => 'editors',
'smartsearch' => 'finder',
'twofactorauthentication' => 'twofactorauth'
);
/**
* Initiates the search and check
*
@ -57,11 +69,21 @@ class JedcheckerRulesXMLinfo extends JEDcheckerRule
// Find all XML files of the extension
$files = JFolder::files($this->basedir, '\.xml$', true, true);
$manifestFound = false;
// Iterate through all the xml files
foreach ($files as $file)
{
// Try to find the license
$this->find($file);
if ($this->find($file))
{
$manifestFound = true;
}
}
if (!$manifestFound)
{
$this->report->addError('', JText::_('COM_JEDCHECKER_INFO_XML_NO_MANIFEST'));
}
}
@ -70,52 +92,231 @@ class JedcheckerRulesXMLinfo extends JEDcheckerRule
*
* @param string $file - The path to the file
*
* @return boolean True if the license was found, otherwise False.
* @return boolean True if the manifest file was found, otherwise False.
*/
protected function find($file)
{
$xml = JFactory::getXml($file);
// Get all the info about the file
$folder_info = pathinfo($file);
// Get the folder path
$folder_path = $folder_info['dirname'];
// Get the folder name
$folder_name = $folder_info['dirname'];
$folder_name_exploded = explode(DIRECTORY_SEPARATOR,$folder_name);
if ( is_array($folder_name_exploded) ) {
$folder_name = end($folder_name_exploded);
}
// Load the language of the extension (if any)
$lang = JFactory::getLanguage();
$lang->load($folder_name,$folder_path);
// Failed to parse the xml file.
// Assume that this is not a extension manifest
if (!$xml)
{
return true;
return false;
}
// Check if this is an extension manifest
// 1.5 uses 'install', 1.6 uses 'extension'
if ($xml->getName() != 'install' && $xml->getName() != 'extension')
// 1.5 uses 'install', 1.6+ uses 'extension'
if ($xml->getName() === 'install')
{
return true;
$this->report->addWarning($file, JText::sprintf('COM_JEDCHECKER_INFO_XML_MANIFEST_OUTDATED'));
}
if ($xml->getName() !== 'extension')
{
return false;
}
// Get extension type
$type = (string) $xml['type'];
// Get extension's element name (simulates work of Joomla's installer)
// Firstly, check for <element> node
if (isset($xml->element))
{
$extension = (string) $xml->element;
}
else
{
// Otherwise, use <name> node or plugin/module attribute in the <files> section
$extension = (string) $xml->name;
if (isset($xml->files))
{
foreach ($xml->files->children() as $child)
{
if (isset($child[$type]))
{
$extension = (string) $child[$type];
}
}
}
}
// Filter extension's element name
$extension = strtolower(JFilterInput::getInstance()->clean($extension, 'cmd'));
// Component's element name starts with com_
if ($type === 'component' && strpos($extension, 'com_') !== 0)
{
$extension = 'com_' . $extension;
}
// Plugin's element name starts with plg_
if ($type === 'plugin' && isset($xml['group']) && strpos($extension, 'plg_') !== 0)
{
$extension = 'plg_' . $xml['group'] . '_' . $extension;
}
// Load the language of the extension (if any)
$lang = JFactory::getLanguage();
// Search for .sys.ini translation file
$langDir = dirname($file);
$langTag = 'en-GB'; // $lang->getDefault();
// Populate list of directories to look for
$lookupLangDirs = array();
if (isset($xml->administration->files['folder']))
{
$lookupLangDirs[] = trim($xml->administration->files['folder'], '/') . '/language/' . $langTag;
}
if (isset($xml->files['folder']))
{
$lookupLangDirs[] = trim($xml->files['folder'], '/') . '/language/' . $langTag;
}
$lookupLangDirs[] = 'language/' . $langTag;
if (isset($xml->administration->languages))
{
$folder = trim($xml->administration->languages['folder'], '/');
foreach ($xml->administration->languages->language as $language)
{
if (trim($language['tag']) === $langTag)
{
$lookupLangDirs[] = trim($folder . '/' . dirname($language), '/');
}
}
}
if (isset($xml->languages))
{
$folder = trim($xml->languages['folder'], '/');
foreach ($xml->languages->language as $language)
{
if (trim($language['tag']) === $langTag)
{
$lookupLangDirs[] = trim($folder . '/' . dirname($language), '/');
}
}
}
$lookupLangDirs[] = '';
$lookupLangDirs = array_unique($lookupLangDirs);
// Looking for language file in specified directories
foreach ($lookupLangDirs as $dir)
{
$langSysFile =
$langDir . '/' .
($dir === '' ? '' : $dir . '/') .
$langTag. '.' . $extension . '.sys.ini';
if (is_file($langSysFile))
{
$loadLanguage = new ReflectionMethod($lang, 'loadLanguage');
$loadLanguage->setAccessible(true);
$loadLanguage->invoke($lang, $langSysFile, $extension);
break;
}
}
// Get the real extension's name now that the language has been loaded
(string) $extension_name = $lang->_($xml->name);
$extensionName = $lang->_((string) $xml->name);
$info[] = JText::sprintf('COM_JEDCHECKER_INFO_XML_NAME_XML', $extension_name);
$info[] = JText::sprintf('COM_JEDCHECKER_INFO_XML_NAME_XML', $extensionName);
$info[] = JText::sprintf('COM_JEDCHECKER_INFO_XML_VERSION_XML', (string) $xml->version);
$info[] = JText::sprintf('COM_JEDCHECKER_INFO_XML_CREATIONDATE_XML', (string) $xml->creationDate);
$this->report->addInfo($file, implode('<br />', $info));
// NM3 - Listing name contains “module” or “plugin”
if (preg_match('/module|plugin/i', $extensionName))
{
$this->report->addError($file, JText::sprintf('COM_JEDCHECKER_INFO_XML_NAME_MODULE_PLUGIN', $extensionName));
}
// The "template" is reserved keyword
if (stripos($extensionName, 'template') !== false)
{
$this->report->addWarning($file, JText::sprintf('COM_JEDCHECKER_INFO_XML_NAME_RESERVED_KEYWORDS', $extensionName));
}
// NM5 - Version in name/title
if (preg_match('/(?:\bversion\b|\d\.\d)/i', $extensionName))
{
$this->report->addError($file, JText::sprintf('COM_JEDCHECKER_INFO_XML_NAME_VERSION', $extensionName));
}
if (stripos($extensionName, 'joomla') === 0)
{
// An extension name can't start with the word "Joomla"
$this->report->addError($file, JText::sprintf('COM_JEDCHECKER_INFO_XML_NAME_JOOMLA', $extensionName));
}
elseif (stripos($extensionName, 'joom') !== false)
{
// Extensions that use "Joomla" or a derivative of Joomla in the extension name need to be licensed by OSM
$this->report->addWarning($file, JText::sprintf('COM_JEDCHECKER_INFO_XML_NAME_JOOMLA_DERIVATIVE', $extensionName));
}
$this->validateDomain($file, (string) $xml->authorUrl);
if ($type === 'package' && (string) $xml->packagerurl !== (string) $xml->authorUrl)
{
$this->validateDomain($file, (string) $xml->packagerurl);
}
if ($type === 'component' && isset($xml->administration->menu))
{
$menuName = $lang->_((string) $xml->administration->menu);
// Do name the Component's admin menu the same as the extension name
if ($extensionName !== $menuName)
{
$this->report->addWarning($file, JText::sprintf('COM_JEDCHECKER_INFO_XML_NAME_ADMIN_MENU', $menuName, $extensionName));
}
}
if ($type === 'plugin')
{
// The name of your plugin must comply with the JED naming conventions - plugins in the form “{Type} - {Extension Name}”.
$parts = explode(' - ', $extensionName, 2);
$extensionNameGroup = isset($parts[1]) ? strtolower(preg_replace('/\s/', '', $parts[0])) : false;
$group = (string) $xml['group'];
if ($extensionNameGroup !== $group && $extensionNameGroup !== str_replace('-', '', $group)
&& !(isset($this->pluginsGroupMap[$extensionNameGroup]) && $this->pluginsGroupMap[$extensionNameGroup] === $group)
)
{
$this->report->addWarning($file, JText::sprintf('COM_JEDCHECKER_INFO_XML_NAME_PLUGIN_FORMAT', $extensionName));
}
}
// All checks passed. Return true
return true;
}
/**
* Check domain name contains "Joomla"/derivative
*
* @param string $file Current file name
* @param string $url URL to validate
*
* @return void
*/
protected function validateDomain($file, $url)
{
$domain = (strpos($url, '//') === false) ? $url : parse_url(trim($url), PHP_URL_HOST);
if (stripos($domain, 'joom') !== false)
{
// Extensions that use "Joomla" or a derivative of Joomla in the domain name need to be licensed by OSM
$this->report->addError($file, JText::sprintf('COM_JEDCHECKER_INFO_XML_URL_JOOMLA_DERIVATIVE', $url, 'https://tm.joomla.org/approved-domains.html'));
}
}
}