├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── README.md ├── bin └── mvi ├── composer.json ├── md5 ├── magento-CE-1.0.0.0 ├── magento-CE-1.1.0.0 ├── magento-CE-1.1.1.0 ├── magento-CE-1.1.2.0 ├── magento-CE-1.1.3.0 ├── magento-CE-1.1.4.0 ├── magento-CE-1.1.5.0 ├── magento-CE-1.1.6.0 ├── magento-CE-1.1.7.0 ├── magento-CE-1.1.8.0 ├── magento-CE-1.2.0.0 ├── magento-CE-1.2.0.1 ├── magento-CE-1.2.0.2 ├── magento-CE-1.2.0.3 ├── magento-CE-1.2.1.0 ├── magento-CE-1.2.1.1 ├── magento-CE-1.2.1.2 ├── magento-CE-1.3.0.0 ├── magento-CE-1.3.1.0 ├── magento-CE-1.3.1.1 ├── magento-CE-1.3.2.0 ├── magento-CE-1.3.2.1 ├── magento-CE-1.3.2.2 ├── magento-CE-1.3.2.3 ├── magento-CE-1.3.2.4 ├── magento-CE-1.3.3.0 ├── magento-CE-1.4.0.0 ├── magento-CE-1.4.0.1 ├── magento-CE-1.4.1.0 ├── magento-CE-1.4.1.1 ├── magento-CE-1.4.2.0 ├── magento-CE-1.5.0.1 ├── magento-CE-1.5.1.0 ├── magento-CE-1.6.0.0 ├── magento-CE-1.6.1.0 ├── magento-CE-1.6.2.0 ├── magento-CE-1.7.0.0 ├── magento-CE-1.7.0.1 ├── magento-CE-1.7.0.2 ├── magento-CE-1.8.0.0 ├── magento-CE-1.8.1.0 ├── magento-CE-1.9.0.0 ├── magento-CE-1.9.0.1 ├── magento-CE-1.9.1.0 ├── magento-CE-1.9.1.1 ├── magento-CE-1.9.2.0 ├── magento-CE-1.9.2.1 ├── magento-CE-1.9.2.2 ├── magento-CE-1.9.2.3 ├── magento-CE-1.9.2.4 ├── magento-CE-1.9.3.0 ├── magento-CE-1.9.3.1 ├── magento-CE-1.9.3.2 ├── magento-CE-1.9.3.3 ├── magento-CE-1.9.3.4 ├── magento-CE-2.0.0 ├── magento-CE-2.0.0-pub ├── magento-CE-2.0.1 ├── magento-CE-2.0.1-pub ├── magento-CE-2.0.2 ├── magento-CE-2.0.2-pub ├── magento-CE-2.0.3 ├── magento-CE-2.0.3-pub ├── magento-CE-2.0.4 ├── magento-CE-2.0.4-pub ├── magento-EE-1.10.0.2 ├── magento-EE-1.10.1.1 ├── magento-EE-1.11.0.2 ├── magento-EE-1.11.2.0 ├── magento-EE-1.12.0.0 ├── magento-EE-1.12.0.1 ├── magento-EE-1.12.0.2 ├── magento-EE-1.13.0.0 ├── magento-EE-1.13.0.2 ├── magento-EE-1.13.1.0 ├── magento-EE-1.14.0.0 ├── magento-EE-1.14.0.1 ├── magento-EE-1.14.1.0 ├── magento-EE-1.14.2.0 ├── magento-EE-1.14.2.1 ├── magento-EE-1.14.2.2 ├── magento-EE-1.14.2.3 ├── magento-EE-1.14.2.4 ├── magento-EE-1.14.3.0 ├── magento-EE-1.14.3.1 ├── magento-EE-1.14.3.2 ├── magento-EE-1.14.3.3 ├── magento-EE-1.14.3.4 └── magento-EE-1.9.1.1 ├── phpcs.xml ├── src ├── Mvi │ ├── Check.php │ └── Command │ │ ├── CheckCommand.php │ │ ├── GenerateCommand.php │ │ ├── MviCommand.php │ │ └── UniqueCommand.php └── bootstrap.php └── version.json /.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /composer.phar 3 | /release 4 | /vendor 5 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | excluded_paths: 3 | - 'bin/*' 4 | checks: 5 | php: true 6 | build_failure_conditions: 7 | - 'elements.rating(<= D).new.exists' 8 | - 'issues.new.exists' 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | branches: 4 | only: 5 | - master 6 | - dev 7 | 8 | php: 9 | - 5.5 10 | - 5.6 11 | - 7.0 12 | - hhvm 13 | 14 | install: 15 | - composer self-update 16 | - composer install -n --prefer-source 17 | 18 | script: 19 | - ./vendor/bin/phpcs --standard=./phpcs.xml -v --encoding=utf-8 ./src 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Magento Version Identification PHP 2 | 3 | [![Packagist](https://img.shields.io/packagist/v/steverobbins/magento-version-identification.svg?style=flat-square)](https://packagist.org/packages/steverobbins/magento-version-identification) 4 | [![Code Quality](https://img.shields.io/scrutinizer/g/steverobbins/magento-version-identification-php.svg?style=flat-square)](https://scrutinizer-ci.com/g/steverobbins/magento-version-identification-php/?branch=master) 5 | [![Build Status](https://img.shields.io/travis/steverobbins/magento-version-identification-php.svg?style=flat-square)](https://travis-ci.org/steverobbins/magento-version-identification-php) 6 | 7 | This is a PHP port of [Magento Version Identification](https://github.com/gwillem/magento-version-identification) 8 | 9 | --- 10 | 11 | See [`version.json`](https://github.com/steverobbins/magento-version-identification-php/blob/master/version.json). 12 | 13 | --- 14 | 15 | # Installation 16 | 17 | ``` 18 | git clone https://github.com/steverobbins/magento-version-identification-php 19 | cd magento-version-identification-php 20 | mkdir release 21 | curl -sS https://getcomposer.org/installer | php 22 | php composer.phar install 23 | ``` 24 | 25 | ## With Composer 26 | 27 | ``` 28 | "require": { 29 | "steverobbins/magento-version-identification": "dev-master" 30 | } 31 | ``` 32 | 33 | # Usage 34 | 35 | Download your desired version(s) of Magento and place them in the `release` folder. They should be named `CE-1.0`, `CE-1.1.0`, `EE-1.14.1.0`, etc. 36 | 37 | Run the `generate` command to create hashes of all\* the files and save them to the `md5` folder. 38 | 39 | ``` 40 | ./bin/mvi generate 41 | ``` 42 | 43 | To update the `version.json` file with unique hashes, run the `unique` command. 44 | 45 | ``` 46 | ./bin/mvi unique 47 | ``` 48 | 49 | To find the edition and version of a Magento installation, use the `check` command. 50 | 51 | ``` 52 | ./bin/mvi check http://demo.magentocommerce.com/ 53 | ``` 54 | -------------------------------------------------------------------------------- /bin/mvi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 2 | 3 | Project coding standards 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Mvi/Check.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2015 Steve Robbins 9 | * @license http://creativecommons.org/licenses/by/4.0/ CC BY 4.0 10 | * @link https://github.com/steverobbins/magento-version-identification-php 11 | */ 12 | 13 | namespace Mvi; 14 | 15 | /** 16 | * Checks a Magento URL and tries to determine the edition and version 17 | */ 18 | class Check 19 | { 20 | /** 21 | * The URL we're checking 22 | * 23 | * @var string 24 | */ 25 | private $url; 26 | 27 | /** 28 | * Initialize 29 | * 30 | * @param string $url 31 | */ 32 | public function __construct($url = null) 33 | { 34 | if ($url !== null) { 35 | $this->setUrl($url); 36 | } 37 | } 38 | 39 | /** 40 | * Set the URL to check 41 | * 42 | * @param string $url 43 | * 44 | * @return Mvi\Check 45 | */ 46 | public function setUrl($url) 47 | { 48 | $this->validateUrl($url); 49 | $this->url = $url; 50 | return $this; 51 | } 52 | 53 | /** 54 | * Get the edition and version for the url 55 | * 56 | * @return array|boolean 57 | */ 58 | public function getInfo() 59 | { 60 | $versions = $this->getVersions(); 61 | foreach ($versions as $file => $hash) { 62 | $md5 = md5(@file_get_contents($this->url . $file)); 63 | if (isset($hash[$md5])) { 64 | return $hash[$md5]; 65 | } 66 | } 67 | return false; 68 | } 69 | 70 | /** 71 | * Get version information from json 72 | * 73 | * @return array 74 | */ 75 | public function getVersions() 76 | { 77 | return json_decode( 78 | file_get_contents(dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'version.json'), 79 | true 80 | ); 81 | } 82 | 83 | /** 84 | * Validate the URL to check 85 | * 86 | * @param string $url 87 | * 88 | * @return void 89 | */ 90 | protected function validateUrl($url) 91 | { 92 | if (!(substr($url, 0, 7) === 'http://' || substr($url, 0, 8) === 'https://')) { 93 | throw new \InvalidArgumentException('The URL must start with "http://" or "https://"'); 94 | } 95 | if (substr($url, -1) !== '/') { 96 | throw new \InvalidArgumentException('The URL must end in a slash (/)'); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Mvi/Command/CheckCommand.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2015 Steve Robbins 9 | * @license http://creativecommons.org/licenses/by/4.0/ CC BY 4.0 10 | * @link https://github.com/steverobbins/magento-version-identification-php 11 | */ 12 | 13 | namespace Mvi\Command; 14 | 15 | use Mvi\Command\MviCommand; 16 | use Mvi\Check; 17 | use Symfony\Component\Console\Input\InputArgument; 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | /** 22 | * Checks the edition and version of a URL 23 | */ 24 | class CheckCommand extends MviCommand 25 | { 26 | /** 27 | * Configure check command 28 | * 29 | * @return void 30 | */ 31 | protected function configure() 32 | { 33 | $this 34 | ->setName('check') 35 | ->setDescription('Check site\'s Magento version') 36 | ->addArgument( 37 | 'url', 38 | InputArgument::REQUIRED, 39 | 'The URL of the Magento application' 40 | ); 41 | } 42 | 43 | /** 44 | * Run check command 45 | * 46 | * @param InputInterface $input 47 | * @param OutputInterface $output 48 | * 49 | * @return void 50 | */ 51 | protected function execute(InputInterface $input, OutputInterface $output) 52 | { 53 | $checker = new Check($input->getArgument('url')); 54 | $info = $checker->getInfo(); 55 | if ($info === false) { 56 | $output->writeln('Unable to retrieve Magento information'); 57 | return; 58 | } 59 | $i = 0; 60 | foreach ($info as $edition => $versions) { 61 | $output->writeln(sprintf('Edition: %s', $edition)); 62 | $output->writeln(sprintf('Version: %s', implode(', ', $versions))); 63 | if ($i++ > 0) { 64 | $output->writeln('OR'); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Mvi/Command/GenerateCommand.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2015 Steve Robbins 9 | * @license http://creativecommons.org/licenses/by/4.0/ CC BY 4.0 10 | * @link https://github.com/steverobbins/magento-version-identification-php 11 | */ 12 | 13 | namespace Mvi\Command; 14 | 15 | use Mvi\Command\MviCommand; 16 | use Symfony\Component\Console\Helper\ProgressBar; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | /** 21 | * Generates useful md5 hashes of files in release/ 22 | */ 23 | class GenerateCommand extends MviCommand 24 | { 25 | const DIR_RELEASE = 'release'; 26 | 27 | /** 28 | * Folders that have files whos has is of use 29 | * 30 | * @var string[] 31 | */ 32 | protected $hashFolders = [ 33 | 'js', 34 | 'media', 35 | 'pub/static', 36 | 'skin', 37 | 'static' 38 | ]; 39 | 40 | /** 41 | * Patterns of file that are of no use here 42 | * 43 | * @var string[] 44 | */ 45 | protected $fileIgnorePatterns = [ 46 | "/\.(htaccess|php)$/", 47 | ]; 48 | 49 | /** 50 | * Configure generate command 51 | * 52 | * @return void 53 | */ 54 | protected function configure() 55 | { 56 | $this 57 | ->setName('generate') 58 | ->setDescription('Generate MD5 hashes from locally stored releases'); 59 | } 60 | 61 | /** 62 | * Run generate command 63 | * 64 | * @param InputInterface $input 65 | * @param OutputInterface $output 66 | * 67 | * @return void 68 | */ 69 | protected function execute(InputInterface $input, OutputInterface $output) 70 | { 71 | $releases = $this->getReleases(); 72 | $releaseCount = count($releases); 73 | if ($releaseCount === 0) { 74 | $output->writeln('No releases were found'); 75 | } 76 | $output->writeln(sprintf('Found %d release(s)', $releaseCount)); 77 | $progressBar = new ProgressBar($output, $releaseCount); 78 | $progressBar->setFormat('[%bar%] %percent%% %message%'); 79 | $progressBar->setMessage('Processing...'); 80 | $progressBar->start(); 81 | foreach ($releases as $release) { 82 | $progressBar->setMessage($release); 83 | if (false === $this->generate($release)) { 84 | $output->writeln('Failed to generate hashes'); 85 | } 86 | $progressBar->advance(); 87 | } 88 | $progressBar->setMessage('Done'); 89 | $progressBar->finish(); 90 | $output->writeln(''); 91 | $output->writeln('Generation complete'); 92 | } 93 | 94 | /** 95 | * Get list of release folders 96 | * 97 | * @return string[] 98 | */ 99 | protected function getReleases() 100 | { 101 | $names = []; 102 | foreach (glob($this->baseDir . DS . self::DIR_RELEASE . DS . '*') as $name) { 103 | $name = explode(DS, $name); 104 | $names[] = $name[count($name) - 1]; 105 | } 106 | return $names; 107 | } 108 | 109 | /** 110 | * Generate the the list of hashes for this release 111 | * 112 | * @param string $release 113 | * 114 | * @return integer|boolean 115 | */ 116 | protected function generate($release) 117 | { 118 | $hashes = []; 119 | foreach ($this->hashFolders as $folder) { 120 | $files = $this->getFiles($release, $folder); 121 | foreach ($files as $file) { 122 | foreach ($this->fileIgnorePatterns as $pattern) { 123 | if (preg_match($pattern, $file)) { 124 | continue 2; 125 | } 126 | } 127 | $hashes[] = $this->getHash($release, $file); 128 | } 129 | } 130 | return file_put_contents( 131 | $this->baseDir . DS . self::DIR_MD5 . DS . $release, 132 | implode("\n", array_merge($hashes, array(''))) 133 | ); 134 | } 135 | 136 | /** 137 | * Gets all files in a specified folder of a release 138 | * 139 | * @param string $release 140 | * @param string $folder 141 | * 142 | * @return string[] 143 | */ 144 | protected function getFiles($release, $folder) 145 | { 146 | $path = $this->baseDir . DS . self::DIR_RELEASE . DS . $release . DS; 147 | $matches = []; 148 | if (is_dir($path . $folder)) { 149 | $directory = new \RecursiveDirectoryIterator($path . $folder . DS); 150 | $iterator = new \RecursiveIteratorIterator($directory); 151 | foreach ($iterator as $file) { 152 | if (in_array($file->getFilename(), array('.', '..'))) { 153 | continue; 154 | } 155 | $matches[] = str_replace($path, '', (string) $file); 156 | } 157 | } 158 | return $matches; 159 | } 160 | 161 | /** 162 | * Gets the md5 has of a file in the release 163 | * 164 | * @param string $release 165 | * @param string $file 166 | * 167 | * @return string 168 | */ 169 | protected function getHash($release, $file) 170 | { 171 | return md5(file_get_contents($this->baseDir . DS . self::DIR_RELEASE . DS . $release . DS . $file)) 172 | . ' ' . $file; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/Mvi/Command/MviCommand.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2015 Steve Robbins 9 | * @license http://creativecommons.org/licenses/by/4.0/ CC BY 4.0 10 | * @link https://github.com/steverobbins/magento-version-identification-php 11 | */ 12 | 13 | namespace Mvi\Command; 14 | 15 | use Symfony\Component\Console\Command\Command; 16 | 17 | class MviCommand extends Command 18 | { 19 | const DIR_MD5 = 'md5'; 20 | 21 | /** 22 | * The base of this application 23 | * 24 | * @var string 25 | */ 26 | protected $baseDir; 27 | 28 | /** 29 | * Constructor. 30 | * 31 | * @param string|null $name The name of the command; passing null means it must be set in configure() 32 | */ 33 | public function __construct($name = null) 34 | { 35 | parent::__construct($name); 36 | $this->baseDir = realpath(__DIR__ . DS . '..' . DS . '..' . DS . '..'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Mvi/Command/UniqueCommand.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2015 Steve Robbins 9 | * @license http://creativecommons.org/licenses/by/4.0/ CC BY 4.0 10 | * @link https://github.com/steverobbins/magento-version-identification-php 11 | */ 12 | 13 | namespace Mvi\Command; 14 | 15 | use Mvi\Command\MviCommand; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | 19 | /** 20 | * Finds unique md5 hashes 21 | */ 22 | class UniqueCommand extends MviCommand 23 | { 24 | const VERSION_DESTINATION = 'version.json'; 25 | 26 | const ACCURACY_FACTOR = 500; 27 | 28 | const EDITION_SHORT_ENTERPRISE = 'EE'; 29 | const EDITION_SHORT_COMMUNITY = 'CE'; 30 | const EDITION_LONG_ENTERPRISE = 'Enterprise'; 31 | const EDITION_LONG_COMMUNITY = 'Community'; 32 | 33 | /** 34 | * Patterns of file that might not be reliable 35 | * 36 | * @var string[] 37 | */ 38 | protected $fileIgnorePatterns = [ 39 | "/\/rwd\//", 40 | "/[^(js|css)]$/", 41 | ]; 42 | 43 | /** 44 | * Configure generate command 45 | * 46 | * @return void 47 | */ 48 | protected function configure() 49 | { 50 | $this 51 | ->setName('unique') 52 | ->setDescription('Find unique md5 hashes and save to file'); 53 | } 54 | 55 | /** 56 | * Run unique command 57 | * 58 | * @param InputInterface $input 59 | * @param OutputInterface $output 60 | * 61 | * @return void 62 | */ 63 | protected function execute(InputInterface $input, OutputInterface $output) 64 | { 65 | $data = $this->collectData(); 66 | $fileHashCounts = $this->buildFileHashCounts($data); 67 | $fingerprints = []; 68 | $tries = 0; 69 | while (count($data) > 0) { 70 | $accuracy = ceil(++$tries / self::ACCURACY_FACTOR); 71 | $file = key($fileHashCounts); 72 | foreach ($data as $release => $value) { 73 | $this->identify($value, $file, $fileHashCounts, $accuracy, $fingerprints, $release, $data, $output); 74 | } 75 | next($fileHashCounts) ?: reset($fileHashCounts); 76 | } 77 | if ($this->saveUniqueVersions($fingerprints)) { 78 | $output->writeln(sprintf('Unique hashes written to %s', self::VERSION_DESTINATION)); 79 | } else { 80 | $output->writeln('Failed to write unique hashes to file'); 81 | } 82 | } 83 | 84 | /** 85 | * Collect all the release hash datas 86 | * 87 | * [ 88 | * 'CE-1.0.0' => [ 89 | * 'abc123' => 'foo.js', 90 | * 'edf456' => 'bar.js', 91 | * ], 92 | * 'CE-1.1.0' => [ ... ] 93 | * ] 94 | * 95 | * @return array 96 | */ 97 | protected function collectData() 98 | { 99 | $data = []; 100 | foreach (glob($this->baseDir . DS . self::DIR_MD5 . DS . 'magento-*') as $release) { 101 | $lines = explode("\n", file_get_contents($release)); 102 | $release = str_replace($this->baseDir . DS . self::DIR_MD5 . DS . 'magento-', '', $release); 103 | $data[$release] = []; 104 | foreach ($lines as $line) { 105 | if (strlen($line) === 0) { 106 | continue; 107 | } 108 | list($hash, $file) = explode(' ', $line); 109 | foreach ($this->fileIgnorePatterns as $pattern) { 110 | if (preg_match($pattern, $file)) { 111 | continue 2; 112 | } 113 | } 114 | $data[$release][$hash] = $file; 115 | } 116 | } 117 | return $data; 118 | } 119 | 120 | /** 121 | * Get the most import files determined by how many unique hashes they have 122 | * 123 | * [ 124 | * 'skin/adminhtml/default/default/boxes.css' => [ 125 | * 'abc123' => [ 126 | * 'CE-1.0' 127 | * ], 128 | * 'efg456' => [ 129 | * 'CE-1.1.0', 130 | * 'CE-1.1.1' 131 | * ], 132 | * ... 133 | * ], 134 | * ... 135 | * ] 136 | * 137 | * @param array $data 138 | * 139 | * @return array 140 | */ 141 | protected function buildFileHashCounts(array $data) 142 | { 143 | $counts = []; 144 | foreach ($data as $release => $value) { 145 | foreach ($value as $hash => $file) { 146 | if (!isset($counts[$file])) { 147 | $counts[$file] = []; 148 | } 149 | if (!isset($counts[$file][$hash])) { 150 | $counts[$file][$hash] = []; 151 | } 152 | $counts[$file][$hash][] = $release; 153 | } 154 | } 155 | uasort($counts, function ($a, $b) { 156 | return count($b) - count($a); 157 | }); 158 | return $counts; 159 | } 160 | 161 | /** 162 | * Take the release short name and expand 163 | * 164 | * @param string $name 165 | * @param array $existing 166 | * 167 | * @return string[] 168 | */ 169 | protected function prepareReleaseName($name, &$existing) 170 | { 171 | list($edition, $version) = explode('-', $name); 172 | switch ($edition) { 173 | case self::EDITION_SHORT_ENTERPRISE: 174 | $edition = self::EDITION_LONG_ENTERPRISE; 175 | break; 176 | case self::EDITION_SHORT_COMMUNITY: 177 | $edition = self::EDITION_LONG_COMMUNITY; 178 | break; 179 | } 180 | if (!is_array($existing)) { 181 | $existing = []; 182 | } 183 | if (!isset($existing[$edition])) { 184 | $existing[$edition] = []; 185 | } 186 | $existing[$edition][] = $version; 187 | } 188 | 189 | /** 190 | * Add file/hash/release combo to fingerprints if accurate enough 191 | * 192 | * @param array $value 193 | * @param string $file 194 | * @param array $fileHashCounts 195 | * @param string $accuracy 196 | * @param array $fingerprints 197 | * @param string $release 198 | * @param array $data 199 | * @param OutputInterface $output 200 | * 201 | * @return void 202 | */ 203 | protected function identify( 204 | array $value, 205 | $file, 206 | array $fileHashCounts, 207 | $accuracy, 208 | &$fingerprints, 209 | $release, 210 | array &$data, 211 | OutputInterface $output 212 | ) { 213 | $fileHash = array_flip($value); 214 | if (isset($fileHash[$file]) && count($fileHashCounts[$file][$fileHash[$file]]) <= $accuracy) { 215 | if (!isset($fingerprints[$file])) { 216 | $fingerprints[$file] = []; 217 | } 218 | $this->prepareReleaseName($release, $fingerprints[$file][$fileHash[$file]]); 219 | $output->writeln(sprintf( 220 | '%s can be identified by %s with hash %s', 221 | $release, 222 | $file, 223 | $fileHash[$file] 224 | )); 225 | unset($data[$release]); 226 | } 227 | } 228 | 229 | /** 230 | * Save fingerprints to file 231 | * 232 | * @param array $fingerprints 233 | * 234 | * @return integer 235 | */ 236 | protected function saveUniqueVersions($fingerprints) 237 | { 238 | uasort($fingerprints, function ($a, $b) { 239 | return count($b) - count($a); 240 | }); 241 | $json = str_replace('\\/', '/', json_encode($fingerprints, JSON_PRETTY_PRINT)); 242 | return file_put_contents($this->baseDir . DS . self::VERSION_DESTINATION, $json); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/bootstrap.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2015 Steve Robbins 9 | * @license http://creativecommons.org/licenses/by/4.0/ CC BY 4.0 10 | * @link https://github.com/steverobbins/magento-version-identification-php 11 | */ 12 | 13 | define('DS', DIRECTORY_SEPARATOR); 14 | 15 | require_once __DIR__ . '/../vendor/autoload.php'; 16 | 17 | use Mvi\Command\CheckCommand; 18 | use Mvi\Command\GenerateCommand; 19 | use Mvi\Command\UniqueCommand; 20 | use Symfony\Component\Console\Application; 21 | 22 | $app = new Application('Magento Version Identification', '1.3.11'); 23 | 24 | $app->add(new CheckCommand); 25 | $app->add(new GenerateCommand); 26 | $app->add(new UniqueCommand); 27 | 28 | $app->run(); 29 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "skin/adminhtml/default/default/boxes.css": { 3 | "0e8a85aee65699c9cfaed8166d2ee678": { 4 | "Community": [ 5 | "1.0.0.0" 6 | ] 7 | }, 8 | "29651cb812ad5a4b916d1da525df09ff": { 9 | "Community": [ 10 | "1.1.0.0" 11 | ] 12 | }, 13 | "d0511b190cdddf865cca7873917f9a69": { 14 | "Community": [ 15 | "1.1.1.0" 16 | ] 17 | }, 18 | "76a565d95fa10e5449bf63549bc5c76b": { 19 | "Community": [ 20 | "1.3.3.0" 21 | ] 22 | }, 23 | "5b537e36cb7b2670500a384f290bcaf8": { 24 | "Community": [ 25 | "1.4.2.0" 26 | ] 27 | }, 28 | "30a39f4046f3daba55cfbe0e1ca44b4c": { 29 | "Community": [ 30 | "1.5.0.1" 31 | ] 32 | }, 33 | "adca1795a4c58ce6a6332ceb2a6c5335": { 34 | "Community": [ 35 | "1.5.1.0" 36 | ] 37 | }, 38 | "1cbeca223c2e15dcaf500caa5d05b4ed": { 39 | "Community": [ 40 | "1.7.0.0" 41 | ] 42 | }, 43 | "dd6fbd6cc6376045b3a62a823af9a361": { 44 | "Enterprise": [ 45 | "1.10.0.2" 46 | ] 47 | }, 48 | "6b5b0372fbeb93675bfabe24d594bd02": { 49 | "Enterprise": [ 50 | "1.10.1.1" 51 | ] 52 | }, 53 | "b497d3538b1c18012455527f267bef53": { 54 | "Enterprise": [ 55 | "1.11.0.2" 56 | ] 57 | }, 58 | "e895117cde7ba3305769bc1317a47818": { 59 | "Enterprise": [ 60 | "1.11.2.0" 61 | ] 62 | }, 63 | "0902e89fb50b22d44f8242954a89300c": { 64 | "Enterprise": [ 65 | "1.12.0.0" 66 | ] 67 | }, 68 | "3c92a14ac461a1314291d4ad91f1f858": { 69 | "Enterprise": [ 70 | "1.13.1.0" 71 | ] 72 | }, 73 | "89c7b659d4e60aabd705af87f0014524": { 74 | "Enterprise": [ 75 | "1.14.1.0" 76 | ] 77 | }, 78 | "cab2c9f5477e36b73c7d6ea36a9ad932": { 79 | "Enterprise": [ 80 | "1.9.1.1" 81 | ] 82 | }, 83 | "84b67457247969a206456565111c456b": { 84 | "Community": [ 85 | "1.1.2.0", 86 | "1.1.3.0", 87 | "1.1.4.0" 88 | ] 89 | }, 90 | "b17593f892e24469429ffd693573778c": { 91 | "Community": [ 92 | "1.1.7.0", 93 | "1.1.8.0" 94 | ] 95 | }, 96 | "6aefb246b1bb817077e8fca6ae53bf2c": { 97 | "Community": [ 98 | "1.2.0.0", 99 | "1.2.0.1", 100 | "1.2.0.2", 101 | "1.2.0.3" 102 | ] 103 | }, 104 | "a2c7f9ddda846ba76220d7bcbe85c985": { 105 | "Community": [ 106 | "1.2.1.0", 107 | "1.2.1.1", 108 | "1.2.1.2" 109 | ] 110 | }, 111 | "28b1eedec9811e496644257f610e2af3": { 112 | "Community": [ 113 | "1.3.1.0", 114 | "1.3.1.1" 115 | ] 116 | }, 117 | "18c9de4b13f66453034ca520b3208309": { 118 | "Community": [ 119 | "1.3.2.0", 120 | "1.3.2.1", 121 | "1.3.2.3", 122 | "1.3.2.4" 123 | ] 124 | }, 125 | "487698cbac89beffa9d2556cc681f571": { 126 | "Community": [ 127 | "1.6.1.0", 128 | "1.6.2.0" 129 | ] 130 | }, 131 | "5903fadb2d1344922df0aafb49791df8": { 132 | "Community": [ 133 | "1.7.0.1", 134 | "1.7.0.2" 135 | ] 136 | }, 137 | "4124f1904f8c3fb40675bbff6268d017": { 138 | "Community": [ 139 | "1.9.0.0", 140 | "1.9.0.1" 141 | ] 142 | }, 143 | "ba8dd746c8468bfd1cff5c77eadc71a4": { 144 | "Community": [ 145 | "1.9.2.0" 146 | ] 147 | }, 148 | "61e47784d7254e531bb6ce3991d68487": { 149 | "Community": [ 150 | "1.9.2.1", 151 | "1.9.2.2" 152 | ] 153 | }, 154 | "8d7c0d6a023b476ff87c5d2b03a0cfa8": { 155 | "Community": [ 156 | "1.9.2.3", 157 | "1.9.2.4" 158 | ] 159 | }, 160 | "e79018e9c03a3deb366d7df7c50e95ec": { 161 | "Community": [ 162 | "1.9.3.0", 163 | "1.9.3.1" 164 | ] 165 | }, 166 | "8a5c088b435dbcf1bbaac9755d4ed45f": { 167 | "Enterprise": [ 168 | "1.12.0.1", 169 | "1.12.0.2" 170 | ] 171 | }, 172 | "ffa8543ece0cc4d7f8093bbea2e29473": { 173 | "Enterprise": [ 174 | "1.13.0.0", 175 | "1.13.0.2" 176 | ] 177 | }, 178 | "31f79aa5159997fa0436c02abe06569d": { 179 | "Enterprise": [ 180 | "1.14.0.0", 181 | "1.14.0.1" 182 | ] 183 | }, 184 | "89e986c50a1efe2e0f1a5f688ca21914": { 185 | "Enterprise": [ 186 | "1.14.2.1", 187 | "1.14.2.2" 188 | ] 189 | }, 190 | "6ff7812c3c20c7d86909e706a9e60bdb": { 191 | "Enterprise": [ 192 | "1.14.2.3", 193 | "1.14.2.4" 194 | ] 195 | }, 196 | "c89fac64edb359d899aa7ae792ec5809": { 197 | "Enterprise": [ 198 | "1.14.3.0", 199 | "1.14.3.1" 200 | ] 201 | } 202 | }, 203 | "js/mage/adminhtml/sales.js": { 204 | "a4296235ba7ad200dd042fa5200c11b0": { 205 | "Community": [ 206 | "1.6.0.0" 207 | ] 208 | }, 209 | "26c8fd113b4e51aeffe200ce7880b67a": { 210 | "Community": [ 211 | "1.8.0.0" 212 | ] 213 | }, 214 | "5656a8c1c646afaaf260a130fe405691": { 215 | "Community": [ 216 | "1.8.1.0" 217 | ] 218 | }, 219 | "a0436f1eee62dded68e0ec860baeb699": { 220 | "Community": [ 221 | "1.9.1.0" 222 | ] 223 | } 224 | }, 225 | "pub/static/frontend/Magento/luma/en_US/Magento_Customer/js/customer-data.js": { 226 | "426087ad2d586c2d2a8f37db856efd52": { 227 | "Community": [ 228 | "2.0.0" 229 | ] 230 | }, 231 | "10134ca2c07663a53dc5444bddaf2c00": { 232 | "Community": [ 233 | "2.0.1" 234 | ] 235 | }, 236 | "2152c967aee1348d551fcf255ca1abc9": { 237 | "Community": [ 238 | "2.0.2" 239 | ] 240 | } 241 | }, 242 | "skin/frontend/base/default/js/opcheckout.js": { 243 | "12372b489c53f35053dddf05aa3eacdd": { 244 | "Community": [ 245 | "1.9.3.2" 246 | ] 247 | }, 248 | "dfb044ff6990969126bf5396947ec0bc": { 249 | "Enterprise": [ 250 | "1.14.3.2" 251 | ] 252 | } 253 | }, 254 | "js/lib/flex.js": { 255 | "eb84fc6c93a9d27823dde31946be8767": { 256 | "Community": [ 257 | "1.4.0.0" 258 | ] 259 | }, 260 | "4040182326f3836f98acabfe1d507960": { 261 | "Community": [ 262 | "1.4.0.1" 263 | ] 264 | } 265 | }, 266 | "js/prototype/validation.js": { 267 | "295494d0966637bdd03e4ec17c2f338c": { 268 | "Community": [ 269 | "1.4.1.0" 270 | ] 271 | }, 272 | "d3252becf15108532d21d45dced96d53": { 273 | "Community": [ 274 | "1.4.1.1" 275 | ] 276 | } 277 | }, 278 | "skin/frontend/enterprise/default/js/opcheckout.js": { 279 | "646f06b35b0f6e6781c07df7a4e4e7c7": { 280 | "Enterprise": [ 281 | "1.14.3.3" 282 | ] 283 | }, 284 | "500a25f1f51aef9e10728124fe6b29f5": { 285 | "Enterprise": [ 286 | "1.14.3.4" 287 | ] 288 | } 289 | }, 290 | "static/_requirejs/adminhtml/Magento/backend/en_US/requirejs-config.js": { 291 | "8140d92726c186d39e98e31bb0021621": { 292 | "Community": [ 293 | "2.0.0" 294 | ] 295 | }, 296 | "9e0c28c4a5d3cc2335a9762ffec7a3ab": { 297 | "Community": [ 298 | "2.0.1" 299 | ] 300 | } 301 | }, 302 | "js/mage/adminhtml/tools.js": { 303 | "ea81bcf8d9b8fcddb27fb9ec7f801172": { 304 | "Community": [ 305 | "1.3.2.2" 306 | ] 307 | } 308 | }, 309 | "js/mage/adminhtml/product.js": { 310 | "e887acfc2f7af09e04f8e99ac6f7180d": { 311 | "Community": [ 312 | "1.3.0.0" 313 | ] 314 | } 315 | }, 316 | "js/mage/adminhtml/form.js": { 317 | "55bf99ca0637cea2692aa3f455b8397f": { 318 | "Community": [ 319 | "1.9.1.1" 320 | ] 321 | } 322 | }, 323 | "skin/adminhtml/default/default/below_ie7.css": { 324 | "e25bd636a8f9ecc6d25d22a752502042": { 325 | "Enterprise": [ 326 | "1.14.2.0" 327 | ] 328 | } 329 | }, 330 | "skin/frontend/default/blue/css/ie7minus.css": { 331 | "92e01e3574aa78b0a3b92bfb8b1c3b28": { 332 | "Community": [ 333 | "1.1.5.0", 334 | "1.1.6.0" 335 | ] 336 | } 337 | }, 338 | "static/adminhtml/Magento/backend/en_US/Magento_Downloadable/js/components/is-downloadable-handler.js": { 339 | "7ed6057d604f72919bbea217f9831e17": { 340 | "Community": [ 341 | "2.0.3", 342 | "2.0.3", 343 | "2.0.4", 344 | "2.0.4" 345 | ] 346 | } 347 | }, 348 | "js/lib/jquery/jquery-1.12.0.js": { 349 | "cd0095b52c4242a8aea3ae91aba35ea8": { 350 | "Community": [ 351 | "1.9.3.3", 352 | "1.9.3.4" 353 | ] 354 | } 355 | }, 356 | "static/frontend/Magento/luma/en_US/Magento_Ui/js/model/messageList.js": { 357 | "c4ac6d653f423fbd7f9d8ea8f2837465": { 358 | "Community": [ 359 | "2.0.2" 360 | ] 361 | } 362 | } 363 | } --------------------------------------------------------------------------------