| Current Path : /home/rtorresani/www/dev/tests/static/framework/Magento/TestFramework/Inspection/ |
| Current File : //home/rtorresani/www/dev/tests/static/framework/Magento/TestFramework/Inspection/WordsFinder.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
/**
* Finder for a list of preconfigured words
*/
namespace Magento\TestFramework\Inspection;
class WordsFinder
{
/**
* List of file extensions, that indicate a binary file
*
* @var array
*/
protected $_binaryExtensions = [
'jpg', 'jpeg', 'png', 'gif', 'swf', 'mp3', 'avi', 'mov', 'flv', 'jar', 'zip',
'eot', 'ttf', 'woff', 'woff2', 'ico', 'svg',
];
/**
* Copyright string which must be present in every non-binary file
*
* @var string
*/
protected $copyrightString = 'Copyright © Magento, Inc. All rights reserved.';
/**
* Copying string which must be present in every non-binary file right after copyright string
*
* @var string
*/
protected $copyingString = 'See COPYING.txt for license details.';
/**
* List of extensions for which copyright check must be skipped
*
* @var array
*/
protected $copyrightSkipExtensions = ['csv', 'json', 'lock', 'md', 'txt'];
/**
* List of paths where copyright check must be skipped
*
* @var array
*/
protected $copyrightSkipList = [
'lib/web/legacy-build.min.js'
];
/**
* Whether copyright presence should be checked or not
*
* @var bool
*/
protected $isCopyrightChecked;
/**
* Words to search for
*
* @var array
*/
protected $_words = [];
/**
* Map of whitelisted paths to whitelisted words
*
* @var array
*/
protected $_whitelist = [];
/**
* Path to base dir, used to calculate relative paths
*
* @var string
*/
protected $_baseDir;
/**
* Component Registrar
*
* @var \Magento\Framework\Component\ComponentRegistrar
*/
protected $componentRegistrar;
/**
* Map of phrase to exclude from the file content
*
* @var array
*/
private $exclude = [];
/**
* @param string|array $configFiles
* @param string $baseDir
* @param \Magento\Framework\Component\ComponentRegistrar $componentRegistrar
* @param bool $isCopyrightChecked
* @throws \Magento\TestFramework\Inspection\Exception
*/
public function __construct($configFiles, $baseDir, $componentRegistrar, $isCopyrightChecked = false)
{
if (!is_dir($baseDir)) {
throw new \Magento\TestFramework\Inspection\Exception("Base directory {$baseDir} does not exist");
}
$this->_baseDir = str_replace('\\', '/', realpath($baseDir));
$this->componentRegistrar = $componentRegistrar;
// Load config files
if (!is_array($configFiles)) {
$configFiles = [$configFiles];
}
foreach ($configFiles as $configFile) {
$this->_loadConfig($configFile);
}
// Add config files to whitelist, as they surely contain banned words
foreach ($configFiles as $configFile) {
$configFile = str_replace('\\', '/', realpath($configFile));
$this->_whitelist[$configFile] = [];
}
$this->_normalizeWhitelistPaths();
// Final verifications
if (!$this->_words) {
throw new \Magento\TestFramework\Inspection\Exception('No words to check');
}
$this->isCopyrightChecked = $isCopyrightChecked;
}
/**
* Load configuration from file, adding words and whitelisted entries to main config
*
* @param string $configFile
* @throws \Magento\TestFramework\Inspection\Exception
*/
protected function _loadConfig($configFile)
{
if (!file_exists($configFile)) {
throw new \Magento\TestFramework\Inspection\Exception("Configuration file {$configFile} does not exist");
}
try {
$xml = new \SimpleXMLElement(file_get_contents($configFile));
} catch (\Exception $e) {
throw new \Magento\TestFramework\Inspection\Exception($e->getMessage(), $e->getCode(), $e);
}
$this->_extractWords($xml)->_extractWhitelist($xml);
}
/**
* Extract words from configuration xml
*
* @param \SimpleXMLElement $configXml
* @return \Magento\TestFramework\Inspection\WordsFinder
* @throws \Magento\TestFramework\Inspection\Exception
*/
protected function _extractWords(\SimpleXMLElement $configXml)
{
$words = [];
$nodes = $configXml->xpath('//config/words/word');
foreach ($nodes as $node) {
$words[] = (string)$node;
}
$words = array_filter($words);
$words = array_merge($this->_words, $words);
$this->_words = array_unique($words);
return $this;
}
/**
* Extract whitelisted entries and words from configuration xml
*
* @param \SimpleXMLElement $configXml
* @return \Magento\TestFramework\Inspection\WordsFinder
* @throws \Magento\TestFramework\Inspection\Exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
protected function _extractWhitelist(\SimpleXMLElement $configXml)
{
// Load whitelist entries
$whitelist = [];
$exclude = [];
$nodes = $configXml->xpath('//config/whitelist/item');
foreach ($nodes as $node) {
$path = $node->xpath('path');
if (!$path) {
throw new \Magento\TestFramework\Inspection\Exception(
'A "path" must be defined for the whitelisted item'
);
}
$component = $node->xpath('component');
if ($component) {
$componentType = $component[0]->xpath('@type')[0];
$componentName = $component[0]->xpath('@name')[0];
$path = $this->componentRegistrar->getPath((string)$componentType, (string)$componentName)
. '/' . (string)$path[0];
} else {
$path = $this->_baseDir . '/' . (string)$path[0];
}
// Words
$words = [];
$wordNodes = $node->xpath('word');
if ($wordNodes) {
foreach ($wordNodes as $wordNode) {
$words[] = (string)$wordNode;
}
}
$whitelist[$path] = $words;
$excludeNodes = $node->xpath('exclude');
$excludes = [];
if ($excludeNodes) {
foreach ($excludeNodes as $extractNode) {
$excludes[] = (string)$extractNode;
}
}
if (isset($exclude[$path])) {
$exclude[$path] = array_merge($excludes, $exclude[$path]);
} else {
$exclude[$path] = $excludes;
}
}
// Merge with already present whitelist
foreach ($whitelist as $newPath => $newWords) {
if (isset($this->_whitelist[$newPath])) {
$newWords = array_merge($this->_whitelist[$newPath], $newWords);
}
$this->_whitelist[$newPath] = array_unique($newWords);
}
foreach ($exclude as $newPath => $newWords) {
if (isset($this->exclude[$newPath])) {
$newWords = array_merge($this->exclude[$newPath], $newWords);
}
$this->exclude[$newPath] = array_unique($newWords);
}
return $this;
}
/**
* Normalize whitelist paths, so that they containt only native directory separators
*/
protected function _normalizeWhitelistPaths()
{
$whitelist = $this->_whitelist;
$this->_whitelist = [];
foreach ($whitelist as $whitelistFile => $whitelistWords) {
$whitelistFile = str_replace('\\', '/', $whitelistFile);
$this->_whitelist[$whitelistFile] = $whitelistWords;
}
}
/**
* Checks the file content and name against the list of words. Do not check content of binary files.
* Exclude whitelisted entries.
*
* @param string $file
* @return array Words, found
*/
public function findWords($file)
{
$foundWords = $this->_findWords($file);
if (!$foundWords) {
return [];
}
return self::_removeWhitelistedWords($file, $foundWords);
}
/**
* Checks the file content and name against the list of words. Do not check content of binary files.
*
* @param string $file
* @return array
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
protected function _findWords($file)
{
$checkContents = !$this->_isBinaryFile($file);
$path = $this->getSearchablePath($file);
$contents = $checkContents ? file_get_contents($file) : '';
if (isset($this->exclude[$file]) && !empty($this->exclude[$file])) {
foreach ($this->exclude[$file] as $stringToEliminate) {
$contents = str_replace($stringToEliminate, "", $contents);
}
}
$foundWords = [];
foreach ($this->_words as $word) {
if (stripos($path, $word) !== false || stripos($contents, $word) !== false) {
$foundWords[] = $word;
}
}
if ($contents && $this->isCopyrightChecked && !$this->isCopyrightCheckSkipped($file)
&& (($copyrightStringPosition = mb_strpos($contents, $this->copyrightString)) === false
|| ($copyingStringPosition = strpos($contents, $this->copyingString)) === false
|| $copyingStringPosition - $copyrightStringPosition - mb_strlen($this->copyrightString) > 10)
) {
$foundWords[] = 'Copyright string is missing';
}
return $foundWords;
}
/**
* @param string $path
* @return bool
*/
protected function isCopyrightCheckSkipped($path)
{
if (in_array(pathinfo($path, PATHINFO_EXTENSION), $this->copyrightSkipExtensions)) {
return true;
}
foreach ($this->copyrightSkipList as $dir) {
if (strpos($path, $dir) !== false) {
return true;
}
}
return false;
}
/**
* Check, whether file is a binary one
*
* @param string $file
* @return bool
*/
protected function _isBinaryFile($file)
{
return in_array(pathinfo($file, PATHINFO_EXTENSION), $this->_binaryExtensions);
}
/**
* Removes whitelisted words from array of found words
*
* @param string $path
* @param array $foundWords
* @return array
*/
protected function _removeWhitelistedWords($path, $foundWords)
{
$path = str_replace('\\', '/', $path);
foreach ($this->_whitelist as $whitelistPath => $whitelistWords) {
if (strncmp($whitelistPath, $path, strlen($whitelistPath)) != 0) {
continue;
}
if (!$whitelistWords) {
// All words are permitted there
return [];
}
$foundWords = array_diff($foundWords, $whitelistWords);
}
return $foundWords;
}
/**
* Return the path for words search
*
* @param string $file
* @return string
*/
protected function getSearchablePath($file)
{
if (strpos($file, $this->_baseDir) === false) {
return $file;
}
return substr($file, strlen($this->_baseDir) + 1);
}
}