7 namespace Fossology\Lib\Util;
10 use GuzzleHttp\Exception\GuzzleException;
11 use GuzzleHttp\RequestOptions;
15 private Client $client;
16 private string $cacheDir;
17 private int $cacheTtl = 86400;
19 public function __construct()
21 $this->client =
new Client([
23 'connect_timeout' => 5,
26 $baseCache = $GLOBALS[
'SysConf'][
'DIRECTORIES'][
'cache'] ?? sys_get_temp_dir();
27 $this->cacheDir = rtrim($baseCache,
'/\\') .
'/util/osselot';
29 if (!is_dir($this->cacheDir)) {
30 @mkdir($this->cacheDir, 0755,
true);
42 if (empty($pkgName)) {
47 $sysConfig = $SysConf[
'SYSCONFIG'];
48 $curatedUrl = $sysConfig[
'OsselotCuratedUrl'];
50 $apiUrl = $curatedUrl .
"?" . rawurlencode($pkgName);
53 $response = $this->client->get($apiUrl, [
55 'Accept' =>
'text/plain, text/html, */*',
56 'User-Agent' =>
'Fossology-OsselotHelper',
59 'connect_timeout' => 10,
62 if ($response->getStatusCode() !== 200) {
66 $responseBody = (string)$response->getBody();
67 if (empty($responseBody)) {
72 $lines = explode(
"\n",
trim($responseBody));
74 foreach ($lines as $line) {
80 if (preg_match(
'/^' . preg_quote($pkgName,
'/') .
'\/version-(.+)$/', $line, $matches)) {
81 $version =
trim($matches[1]);
82 if (!empty($version)) {
83 $versions[] = $version;
88 $versions = array_unique($versions);
89 sort($versions, SORT_NATURAL);
111 if (empty($pkgName) || empty($version)) {
112 throw new \InvalidArgumentException(
'Package name and version cannot be empty');
116 $sysConfig = $SysConf[
'SYSCONFIG'];
117 $githubRoot = $sysConfig[
'OsselotPackageAnalysisUrl'];
118 $primaryDomain = $sysConfig[
'OsselotPrimaryDomain'];
119 $fallbackDomain = $sysConfig[
'OsselotFallbackDomain'];
121 $safeName = preg_replace(
'/[^a-zA-Z0-9_.\-]/',
'_', $pkgName);
122 $safeVer = preg_replace(
'/[^a-zA-Z0-9_.\-]/',
'_', $version);
123 $cacheFile =
"{$this->cacheDir}/{$safeName}_{$safeVer}.rdf";
125 if (is_file($cacheFile) && (time() - filemtime($cacheFile) < $this->cacheTtl)) {
130 '%s/version-%s/%s-%s.spdx.rdf.xml',
131 rawurlencode($pkgName),
132 rawurlencode($version),
133 rawurlencode($pkgName),
134 rawurlencode($version)
138 "{$githubRoot}/{$relPath}",
139 "{$githubRoot}/{$relPath}.gz",
140 str_replace($primaryDomain, $fallbackDomain,
"{$githubRoot}/{$relPath}"),
144 RequestOptions::HEADERS => [
145 'Accept' =>
'application/rdf+xml, application/xml, text/xml',
146 'User-Agent' =>
'Fossology-OsselotHelper',
148 RequestOptions::HTTP_ERRORS =>
false,
149 RequestOptions::CONNECT_TIMEOUT => 10,
150 RequestOptions::TIMEOUT => 30,
153 foreach ($candidates as $url) {
155 $response = $this->client->get($url, $options);
157 if ($response->getStatusCode() !== 200) {
161 $body = (string) $response->getBody();
166 if (str_ends_with($url,
'.gz')) {
167 $decompressed = @gzdecode($body);
168 if ($decompressed ===
false) {
171 $body = $decompressed;
178 if (!is_dir($this->cacheDir)) {
179 @mkdir($this->cacheDir, 0755,
true);
182 if (file_put_contents($cacheFile, $body) !==
false) {
198 $previousUseInternalErrors = libxml_use_internal_errors(
true);
199 libxml_clear_errors();
201 $doc = simplexml_load_string($content);
202 $errors = libxml_get_errors();
204 libxml_use_internal_errors($previousUseInternalErrors);
205 libxml_clear_errors();
207 return $doc !==
false && empty($errors);
217 if (!is_dir($this->cacheDir)) {
221 foreach (glob($this->cacheDir .
'/*.rdf') as $file) {
222 if (is_file($file)) {
fetchSpdxFile(string $pkgName, string $version)
isValidXml(string $content)
getVersions(string $pkgName)
char * trim(char *ptext)
Trimming whitespace.