33
2
mirror of https://github.com/joomla-extensions/jedchecker.git synced 2024-11-17 02:25:10 +00:00

Merge pull request #204 from dryabov/patch-71

Improve validation of XML manifests
This commit is contained in:
Denis Ryabov 2023-07-27 19:43:50 +03:00 committed by GitHub
commit 0c41b95ad2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 136 additions and 3 deletions

View File

@ -117,10 +117,14 @@ COM_JEDCHECKER_MANIFEST_MENU_UNUSED_ATTRIBUTE="Menu item attribute '%s' is not u
COM_JEDCHECKER_MANIFEST_MISSED_METHOD_UPGRADE="Without the method="upgrade" attribute the extension package cannot be upgraded" COM_JEDCHECKER_MANIFEST_MISSED_METHOD_UPGRADE="Without the method="upgrade" attribute the extension package cannot be upgraded"
COM_JEDCHECKER_MANIFEST_MISSED_ATTRIBUTE="The node <%1$s> doesn't contain required '%2$s' attribute" COM_JEDCHECKER_MANIFEST_MISSED_ATTRIBUTE="The node <%1$s> doesn't contain required '%2$s' attribute"
COM_JEDCHECKER_MANIFEST_UNKNOWN_ATTRIBUTE_VALUE="The node <%1$s> has attribute '%2$s' with unknown value "%3$s"" COM_JEDCHECKER_MANIFEST_UNKNOWN_ATTRIBUTE_VALUE="The node <%1$s> has attribute '%2$s' with unknown value "%3$s""
COM_JEDCHECKER_MANIFEST_MULTIPLE_ATTRIBUTES="The <files> node contains multiple elements with '%s' attribute"
COM_JEDCHECKER_MANIFEST_MODULE_ELEMENT_MISMATCH="The value of <element> node doesn't match value of 'module' attribute in the <files> elements"
COM_JEDCHECKER_MANIFEST_MISSED_ELEMENT_ATTRIBUTE="The <files> node doesn't contain element with '%s' attribute"
COM_JEDCHECKER_XML_FILES="XML Files references" COM_JEDCHECKER_XML_FILES="XML Files references"
COM_JEDCHECKER_XML_FILES_DESC="Check for incorrect files and folders references in the XML manifest" COM_JEDCHECKER_XML_FILES_DESC="Check for incorrect files and folders references in the XML manifest"
COM_JEDCHECKER_XML_FILES_FILE_NOT_FOUND="File not found: %s" COM_JEDCHECKER_XML_FILES_FILE_NOT_FOUND="File not found: %s"
COM_JEDCHECKER_XML_FILES_FOLDER_NOT_FOUND="Folder not found: %s" COM_JEDCHECKER_XML_FILES_FOLDER_NOT_FOUND="Folder not found: %s"
COM_JEDCHECKER_XML_FILES_EMPTY_LIST="The node %s is empty"
COM_JEDCHECKER_LANG="Language files" COM_JEDCHECKER_LANG="Language files"
COM_JEDCHECKER_LANG_DESC="Validates language files" COM_JEDCHECKER_LANG_DESC="Validates language files"
COM_JEDCHECKER_LANG_INCORRECT_EOL="Incorrect end-of-line character found. Convert file to Unix EOL (\n) format." COM_JEDCHECKER_LANG_INCORRECT_EOL="Incorrect end-of-line character found. Convert file to Unix EOL (\n) format."

View File

@ -105,7 +105,7 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
$xml = simplexml_load_file($file); $xml = simplexml_load_file($file);
// Failed to parse the xml file. // Failed to parse the xml file.
// Assume that this is not a extension manifest // Assume that this is not an extension manifest
if (!$xml) if (!$xml)
{ {
return false; return false;
@ -125,6 +125,7 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
if (isset($xml->files)) if (isset($xml->files))
{ {
$node = $xml->files; $node = $xml->files;
$this->checkNotEmpty($node);
// Get path to site files from "folder" attribute // Get path to site files from "folder" attribute
$sitedir = $this->getSourceFolder($node); $sitedir = $this->getSourceFolder($node);
@ -138,6 +139,8 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
if (isset($xml->media)) if (isset($xml->media))
{ {
$node = $xml->media; $node = $xml->media;
$this->checkNotEmpty($node);
$dir = $this->getSourceFolder($node); $dir = $this->getSourceFolder($node);
$this->checkFiles($node->filename, $dir); $this->checkFiles($node->filename, $dir);
@ -149,6 +152,8 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
if (isset($xml->fonts)) if (isset($xml->fonts))
{ {
$node = $xml->fonts; $node = $xml->fonts;
$this->checkNotEmpty($node);
$dir = $this->getSourceFolder($node); $dir = $this->getSourceFolder($node);
$this->checkFiles($node->filename, $dir); $this->checkFiles($node->filename, $dir);
@ -160,6 +165,8 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
if (isset($xml->languages)) if (isset($xml->languages))
{ {
$node = $xml->languages; $node = $xml->languages;
$this->checkNotEmpty($node);
$dir = $this->getSourceFolder($node); $dir = $this->getSourceFolder($node);
$this->checkFiles($node->language, $dir); $this->checkFiles($node->language, $dir);
@ -171,6 +178,7 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
if (isset($xml->administration->files)) if (isset($xml->administration->files))
{ {
$node = $xml->administration->files; $node = $xml->administration->files;
$this->checkNotEmpty($node);
// Get path to admin files from "folder" attribute // Get path to admin files from "folder" attribute
$admindir = $this->getSourceFolder($node); $admindir = $this->getSourceFolder($node);
@ -184,6 +192,8 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
if (isset($xml->administration->media)) if (isset($xml->administration->media))
{ {
$node = $xml->administration->media; $node = $xml->administration->media;
$this->checkNotEmpty($node);
$dir = $this->getSourceFolder($node); $dir = $this->getSourceFolder($node);
$this->checkFiles($node->filename, $dir); $this->checkFiles($node->filename, $dir);
@ -195,6 +205,8 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
if (isset($xml->administration->languages)) if (isset($xml->administration->languages))
{ {
$node = $xml->administration->languages; $node = $xml->administration->languages;
$this->checkNotEmpty($node);
$dir = $this->getSourceFolder($node); $dir = $this->getSourceFolder($node);
$this->checkFiles($node->language, $dir); $this->checkFiles($node->language, $dir);
@ -205,6 +217,8 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
if (isset($xml->fileset->files)) if (isset($xml->fileset->files))
{ {
$node = $xml->fileset->files; $node = $xml->fileset->files;
$this->checkNotEmpty($node);
$dir = $this->getSourceFolder($node); $dir = $this->getSourceFolder($node);
$this->checkFiles($node->filename, $dir); $this->checkFiles($node->filename, $dir);
@ -216,6 +230,8 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
if (isset($xml->api->files)) if (isset($xml->api->files))
{ {
$node = $xml->api->files; $node = $xml->api->files;
$this->checkNotEmpty($node);
$dir = $this->getSourceFolder($node); $dir = $this->getSourceFolder($node);
$this->checkFiles($node->filename, $dir); $this->checkFiles($node->filename, $dir);
@ -347,6 +363,27 @@ class JedcheckerRulesXMLFiles extends JEDcheckerRule
return ''; return '';
} }
/**
* Check list of files/folders is not empty
*
* @param SimpleXMLElement $node Node to check
*
* @return void
*/
protected function checkNotEmpty($node)
{
if (count($node->children()) === 0) {
$path = array();
foreach ($node->xpath("ancestor-or-self::*") as $p)
{
$path[] = $p->getName();
}
$this->warnings[] = JText::sprintf('COM_JEDCHECKER_XML_FILES_EMPTY_LIST', implode('/', $path));
}
}
/** /**
* Check files exist * Check files exist
* *

View File

@ -132,7 +132,7 @@ class JedcheckerRulesXMLManifest extends JEDcheckerRule
$xml = simplexml_load_file($file); $xml = simplexml_load_file($file);
// Failed to parse the xml file. // Failed to parse the xml file.
// Assume that this is not a extension manifest // Assume that this is not an extension manifest
if (!$xml) if (!$xml)
{ {
return false; return false;
@ -178,12 +178,67 @@ class JedcheckerRulesXMLManifest extends JEDcheckerRule
{ {
$this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_UNKNOWN_ATTRIBUTE_VALUE', $xml->getName(), 'client', $client)); $this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_UNKNOWN_ATTRIBUTE_VALUE', $xml->getName(), 'client', $client));
} }
if ($type === 'module')
{
// Either <element> or "module" attribute (once only) should be present
$elements = $this->collectElements($xml->files, $type);
if (count($elements) >= 2)
{
$this->report->addWarning($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_MULTIPLE_ATTRIBUTES', 'module'));
}
if (isset($xml->element))
{
$element = (string) $xml->element;
if (count($elements) && $elements[0] !== $element)
{
$this->report->addWarning($file, JText::_('COM_JEDCHECKER_MANIFEST_MODULE_ELEMENT_MISMATCH'));
}
}
else
{
if (count($elements) === 0)
{
$this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_MISSED_ELEMENT_ATTRIBUTE', 'module'));
}
}
}
break;
case 'plugin':
// "plugin" attribute (once only) should be present
$elements = $this->collectElements($xml->files, $type);
if (count($elements) >= 2)
{
$this->report->addWarning($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_MULTIPLE_ATTRIBUTES', 'plugin'));
}
if (count($elements) === 0)
{
$this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_MISSED_ELEMENT_ATTRIBUTE', 'plugin'));
}
break; break;
case 'package': case 'package':
// Check type-specific attributes // Check type-specific attributes
foreach ($xml->files->file as $item) foreach ($xml->files->children() as $item)
{ {
if (!isset($item['type']))
{
$this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_MISSED_ATTRIBUTE', $item->getName(), 'type'));
}
if (!isset($item['id']))
{
$this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_MISSED_ATTRIBUTE', $item->getName(), 'id'));
}
switch ((string) $item['type']) switch ((string) $item['type'])
{ {
case 'plugin': case 'plugin':
@ -431,4 +486,29 @@ class JedcheckerRulesXMLManifest extends JEDcheckerRule
} }
} }
} }
/**
* Collect values of $type attribute from all children
* @param SimpleXMLElement $node XML node <files>
* @param string $type Extension's type (plugin or module)
*
* @return array List of found attributes
*/
protected function collectElements($node, $type)
{
$elements = array();
if (isset($node))
{
foreach ($node->children() as $child)
{
if (isset($child[$type]))
{
$elements[] = (string) $child[$type];
}
}
}
return $elements;
}
} }

View File

@ -87,6 +87,9 @@
"files:file": [ "files:file": [
"module" "module"
], ],
"folder": [
"module"
],
"languages": [ "languages": [
"folder" "folder"
], ],

View File

@ -75,6 +75,12 @@
"id", "id",
"type" "type"
], ],
"folder": [
"client",
"group",
"id",
"type"
],
"languages": [ "languages": [
"folder" "folder"
], ],

View File

@ -88,6 +88,9 @@
"files:file": [ "files:file": [
"plugin" "plugin"
], ],
"folder": [
"plugin"
],
"languages": [ "languages": [
"folder" "folder"
], ],