<?php
 namespace Modules\Admin\About\Model; class LicenseReader { protected const LICENSE_FILE_PATTERNS = [ 'LICENSE', 'LICENSE.md', 'LICENSE.txt', 'LICENCE', 'LICENCE.md', 'LICENCE.txt', 'COPYING', 'COPYING.md', 'COPYING.txt', ]; public function loadFromSources(SourcesCollector $collector): array { $libraries = []; foreach ($collector->getSources() as $sourceEntry) { $parsed = $this->parseComposerLock($sourceEntry['composerLockPath'], $sourceEntry['vendorPath'], $sourceEntry['source']); foreach ($parsed as $lib) { $key = $lib['name']; if (isset($libraries[$key])) { if (strpos($libraries[$key]['source'], $lib['source']) === false) { $libraries[$key]['source'] .= ', ' . $lib['source']; } } else { $libraries[$key] = $lib; } } } foreach ($collector->getManualLibraries() as $lib) { $key = $lib['name']; if (isset($libraries[$key])) { if (strpos($libraries[$key]['source'], $lib['source']) === false) { $libraries[$key]['source'] .= ', ' . $lib['source']; } } else { $libraries[$key] = $lib; } } ksort($libraries); return array_values($libraries); } protected function parseComposerLock(string $composerLockPath, string $vendorPath, string $sourceLabel): array { if (!is_file($composerLockPath)) { return []; } $content = file_get_contents($composerLockPath); if ($content === false) { return []; } $data = json_decode($content, true); if (!is_array($data) || empty($data['packages'])) { return []; } $libraries = []; foreach ($data['packages'] as $package) { $name = $package['name'] ?? ''; if (!$name) { continue; } $libraries[$name] = [ 'name' => $name, 'version' => $package['version'] ?? '—', 'license' => !empty($package['license']) ? implode(', ', $package['license']) : '—', 'description' => $package['description'] ?? '—', 'url' => $this->resolveUrl($package), 'licenseText' => $this->readLicenseText($vendorPath, $name), 'source' => $sourceLabel, ]; } return $libraries; } protected function resolveUrl(array $package): ?string { if (!empty($package['homepage'])) { return $package['homepage']; } if (!empty($package['support']['source'])) { return $package['support']['source']; } return null; } protected function readLicenseText(string $vendorPath, string $packageName): string { $packageDir = rtrim($vendorPath, '/\\') . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $packageName); if (!is_dir($packageDir)) { return 'License text not available.'; } $files = scandir($packageDir); if ($files === false) { return 'License text not available.'; } $filesLower = array_combine( array_map('strtolower', $files), $files ); foreach (self::LICENSE_FILE_PATTERNS as $pattern) { $patternLower = strtolower($pattern); if (isset($filesLower[$patternLower])) { $filePath = $packageDir . DIRECTORY_SEPARATOR . $filesLower[$patternLower]; $text = file_get_contents($filePath); if ($text !== false) { return $text; } } } return 'License text not available.'; } } 