FOSSology  4.4.0
Open Source License Compliance by Open Source Software
SpdxTwoImportSource.php
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2015-2017 Siemens AG
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 namespace Fossology\ReportImport;
8 
10 use EasyRdf\Graph;
11 require_once 'ReportImportData.php';
12 require_once 'ReportImportDataItem.php';
13 require_once 'ImportSource.php';
14 
16 {
17  const TERMS = 'http://spdx.org/rdf/terms#';
18  const SPDX_URL = 'http://spdx.org/licenses/';
19  const SYNTAX_NS = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
20 
22  private $filename;
24  private $uri;
26  private $graph;
28  private $index;
30  private $licenseRefPrefix = "LicenseRef-";
31 
32  function __construct($filename, $uri = null)
33  {
34  $this->filename = $filename;
35  $this->uri = $uri;
36  }
37 
41  public function parse()
42  {
43  $this->graph = $this->loadGraph($this->filename, $this->uri);
44  $this->index = $this->loadIndex($this->graph);
45  return true;
46  }
47 
48  private function loadGraph($filename, $uri = null)
49  {
51  $graph = new Graph();
52  $graph->parseFile($filename, 'rdfxml', $uri);
53  return $graph;
54  }
55 
56  private function loadIndex($graph)
57  {
58  return $graph->toRdfPhp();
59  }
60 
64  public function getAllFiles()
65  {
66  $fileIds = array();
67  foreach ($this->index as $subject => $property){
68  if ($this->isPropertyAFile($property))
69  {
70  $fileIds[$subject] = $this->getFileName($property);
71  }
72  }
73  return $fileIds;
74  }
75 
81  private function isPropertyOfType(&$property, $type)
82  {
83  $key = self::SYNTAX_NS . 'type';
84  $target = self::TERMS . $type;
85 
86  return is_array ($property) &&
87  array_key_exists($key, $property) &&
88  sizeof($property[$key]) === 1 &&
89  $property[$key][0]['type'] === "uri" &&
90  $property[$key][0]['value'] === $target;
91  }
92 
97  private function isPropertyAFile(&$property)
98  {
99  return $this->isPropertyOfType($property, 'File');
100  }
101 
106  public function getHashesMap($fileid)
107  {
108  if ($this->isPropertyAFile($property))
109  {
110  return array();
111  }
112 
113  $hashItems = $this->getValues($fileid, 'checksum');
114 
115  $hashes = array();
116  $keyAlgo = self::TERMS . 'algorithm';
117  $algoKeyPrefix = self::TERMS . 'checksumAlgorithm_';
118  $keyAlgoVal = self::TERMS . 'checksumValue';
119  foreach ($hashItems as $hashItem)
120  {
121  $algorithm = $hashItem[$keyAlgo][0]['value'];
122  if(substr($algorithm, 0, strlen($algoKeyPrefix)) === $algoKeyPrefix)
123  {
124  $algorithm = substr($algorithm, strlen($algoKeyPrefix));
125  }
126  $hashes[$algorithm] = $hashItem[$keyAlgoVal][0]['value'];
127  }
128 
129  return $hashes;
130  }
131 
138  private function getValue($propertyOrId, $key, $default=null)
139  {
140  $values = $this->getValues($propertyOrId, $key);
141  if(sizeof($values) === 1)
142  {
143  return $values[0];
144  }
145  return $default;
146  }
147 
153  private function getValues($propertyOrId, $key)
154  {
155  if (is_string($propertyOrId))
156  {
157  $property = $this->index[$propertyOrId];
158  }
159  else
160  {
161  $property = $propertyOrId;
162  }
163 
164  $key = self::TERMS . $key;
165  if (is_array($property) && isset($property[$key]))
166  {
167  $values = array();
168  foreach($property[$key] as $entry)
169  {
170  if($entry['type'] === 'literal')
171  {
172  $values[] = $entry['value'];
173  }
174  elseif($entry['type'] === 'uri')
175  {
176  if(array_key_exists($entry['value'],$this->index))
177  {
178  $values[$entry['value']] = $this->index[$entry['value']];
179  }
180  else
181  {
182  $values[] = $entry['value'];
183  }
184  }
185  elseif($entry['type'] === 'bnode')
186  {
187  $values[$entry['value']] = $this->index[$entry['value']];
188  }
189  else
190  {
191  error_log("ERROR: can not handle entry=[".$entry."] of type=[" . $entry['type'] . "]");
192  }
193  }
194  return $values;
195  }
196  return array();
197  }
198 
203  private function getFileName($propertyOrId)
204  {
205  return $this->getValue($propertyOrId, 'fileName');
206  }
207 
212  public function getConcludedLicenseInfoForFile($propertyId)
213  {
214  return $this->getLicenseInfoForFile($propertyId, 'licenseConcluded');
215  }
216 
221  public function getLicenseInfoInFileForFile($propertyId)
222  {
223  return $this->getLicenseInfoForFile($propertyId, 'licenseInfoInFile');
224  }
225 
226  private function stripLicenseRefPrefix($licenseId)
227  {
228  if(substr($licenseId, 0, strlen($this->licenseRefPrefix)) === $this->licenseRefPrefix)
229  {
230  return urldecode(substr($licenseId, strlen($this->licenseRefPrefix)));
231  }
232  else
233  {
234  return urldecode($licenseId);
235  }
236  }
237 
238  private function isNotNoassertion($str)
239  {
240  return ! ( strtolower($str) === self::TERMS."noassertion" ||
241  strtolower($str) === "http://spdx.org/licenses/noassertion" );
242  }
243 
244  private function parseLicenseId($licenseId)
245  {
246  if (!is_string($licenseId))
247  {
248  error_log("ERROR: Id not a string: ".$licenseId);
249  return array();
250  }
251  if (strtolower($licenseId) === self::TERMS."noassertion" ||
252  strtolower($licenseId) === "http://spdx.org/licenses/noassertion")
253  {
254  return array();
255  }
256 
257  $license = $this->index[$licenseId];
258 
259  if ($license)
260  {
261  return $this->parseLicense($license);
262  }
263  elseif(substr($licenseId, 0, strlen(self::SPDX_URL)) === self::SPDX_URL)
264  {
265  $spdxId = urldecode(substr($licenseId, strlen(self::SPDX_URL)));
266  $item = new ReportImportDataItem($spdxId);
267  return array($item);
268  }
269  else
270  {
271  error_log("ERROR: can not handle license with ID=".$licenseId);
272  return array();
273  }
274  }
275 
276  private function parseLicense($license)
277  {
278  if (is_string($license))
279  {
280  return $this->parseLicenseId($license);
281  }
282  elseif ($this->isPropertyOfType($license, 'ExtractedLicensingInfo'))
283  {
284  $licenseId = $this->stripLicenseRefPrefix($this->getValue($license,'licenseId'));
285 
286  if(strlen($licenseId) > 33 &&
287  substr($licenseId, -33, 1) === "-" &&
288  ctype_alnum(substr($licenseId, -32)))
289  {
290  $licenseId = substr($licenseId, 0, -33);
291  $item = new ReportImportDataItem($licenseId);
292  $item->setCustomText($this->getValue($license,'extractedText'));
293  return array($item);
294 
295  }
296  else
297  {
298  $item = new ReportImportDataItem($licenseId);
299  $item->setLicenseCandidate($this->getValue($license,'name', $licenseId),
300  $this->getValue($license,'extractedText'),
301  strpos($this->getValue($license,'licenseId'), $this->licenseRefPrefix));
302  return array($item);
303  }
304  }
305  elseif ($this->isPropertyOfType($license, 'License') ||
306  $this->isPropertyOfType($license, 'ListedLicense'))
307  {
308  $licenseId = $this->stripLicenseRefPrefix($this->getValue($license,'licenseId'));
309  $item = new ReportImportDataItem($licenseId);
310  $item->setLicenseCandidate($this->getValue($license,'name', $licenseId),
311  $this->getValue($license,'licenseText'),
312  strpos($this->getValue($license,'licenseId'), $this->licenseRefPrefix));
313  return array($item);
314  }
315  elseif ($this->isPropertyOfType($license, 'DisjunctiveLicenseSet') ||
316  $this->isPropertyOfType($license, 'ConjunctiveLicenseSet')
317  )
318  {
319  $output = array();
320  $subLicenses = $this->getValues($license, 'member');
321  if (sizeof($subLicenses) > 1 &&
322  $this->isPropertyOfType($license, 'DisjunctiveLicenseSet'))
323  {
324  $output[] = new ReportImportDataItem("Dual-license");
325  }
326  foreach($subLicenses as $subLicense)
327  {
328  $innerOutput = $this->parseLicense($subLicense);
329  foreach($innerOutput as $innerItem)
330  {
331  $output[] = $innerItem;
332  }
333  }
334  return $output;
335  }
336  elseif ($this->isPropertyOfType($license, 'OrLaterOperator'))
337  {
338  $output = array();
339  $subLicenses = $this->getValues($license, 'member');
340  foreach($subLicenses as $subLicense) {
342  $innerOutput = $this->parseLicense($subLicense);
343  foreach($innerOutput as $innerItem)
344  {
346  $item = new ReportImportDataItem($innerItem->getLicenseId() . "+");
347 
348  $innerLicenseCandidate = $innerItem->getLicenseCandidate();
349  $item->setLicenseCandidate($innerLicenseCandidate->getFullName() . " or later",
350  $innerLicenseCandidate->getText(),
351  false);
352  $output[] = $item;
353  }
354  }
355  return $output;
356  }
357  else
358  {
359  error_log("ERROR: can not handle license=[".$license."] of type=[".gettype($license)."]");
360  return array();
361  }
362  }
363 
369  private function getLicenseInfoForFile($propertyId, $kind)
370  {
371  $property = $this->index[$propertyId];
372  $licenses = $this->getValues($property, $kind);
373 
374  $output = array();
375  foreach ($licenses as $license)
376  {
377  $innerOutput = $this->parseLicense($license);
378  foreach($innerOutput as $innerItem)
379  {
380  $output[] = $innerItem;
381  }
382  }
383  return $output;
384  }
385 
386  private function getCopyrightTextsForFile($propertyId)
387  {
388  return array_filter(
389  array_map(
390  'trim',
391  $this->getValues($propertyId, "copyrightText")) ,
392  array($this, "isNotNoassertion"));
393  }
394 
395  public function getDataForFile($propertyId)
396  {
397  return new ReportImportData($this->getLicenseInfoInFileForFile($propertyId),
398  $this->getConcludedLicenseInfoForFile($propertyId),
399  $this->getCopyrightTextsForFile($propertyId));
400  }
401 }
getValue($propertyOrId, $key, $default=null)