FOSSology  4.5.1
Open Source License Compliance by Open Source Software
spdx.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2015-2016,2023 Siemens AG
4  SPDX-FileCopyrightText: © 2017 TNG Technology Consulting GmbH
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
43 namespace Fossology\Spdx;
44 
65 use Twig\Environment;
66 
67 include_once(__DIR__ . "/spdxutils.php");
68 
69 include_once(__DIR__ . "/version.php");
70 include_once(__DIR__ . "/services.php");
71 
76 class SpdxAgent extends Agent
77 {
78 
79  const OUTPUT_FORMAT_KEY = "outputFormat";
80  const DEFAULT_OUTPUT_FORMAT = "spdx2";
81  const AVAILABLE_OUTPUT_FORMATS = "spdx2,spdx2tv,dep5,spdx2csv,spdx3jsonld,spdx3json,spdx3rdf,spdx3tv";
82  const UPLOAD_ADDS = "uploadsAdd";
83  const DATA_LICENSE = "CC0-1.0";
84 
88  private $uploadDao;
92  private $clearingDao;
96  private $licenseDao;
100  protected $dbManager;
104  protected $renderer;
108  private $licenseMap;
128  private $reportutils;
132  protected $agentNames = AgentRef::AGENT_LIST;
136  protected $filebasename = null;
140  protected $uri;
144  protected $filename;
149  private $licensesInDocument = [];
162 
163  function __construct()
164  {
165  // deduce the agent name from the command line arguments
166  $args = getopt("", array(self::OUTPUT_FORMAT_KEY.'::'));
167  $agentName = "";
168  if (array_key_exists(self::OUTPUT_FORMAT_KEY, $args)) {
169  $agentName = trim($args[self::OUTPUT_FORMAT_KEY]);
170  }
171  if (empty($agentName)) {
173  }
174 
175  parent::__construct($agentName, AGENT_VERSION, AGENT_REV);
176 
177  $this->uploadDao = $this->container->get('dao.upload');
178  $this->clearingDao = $this->container->get('dao.clearing');
179  $this->licenseDao = $this->container->get('dao.license');
180  $this->dbManager = $this->container->get('db.manager');
181  $this->renderer = $this->container->get('twig.environment');
182  $this->renderer->setCache(false);
183 
184  $this->agentSpecifLongOptions[] = self::UPLOAD_ADDS.':';
185  $this->agentSpecifLongOptions[] = self::OUTPUT_FORMAT_KEY.':';
186 
187  $this->licenseClearedGetter = new LicenseClearedGetter();
188  $this->licenseMainGetter = new LicenseMainGetter();
189  $this->obligationsGetter = new ObligationsGetter();
190  $this->reportutils = new ReportUtils();
191  }
192 
198  protected function preWorkOnArgs($args)
199  {
200  if ((!array_key_exists(self::OUTPUT_FORMAT_KEY, $args)
201  || $args[self::OUTPUT_FORMAT_KEY] === "")
202  && array_key_exists(self::UPLOAD_ADDS,$args)) {
203  $args = SpdxUtils::preWorkOnArgsFlp($args,self::UPLOAD_ADDS,self::OUTPUT_FORMAT_KEY);
204  } else {
205  if (!array_key_exists(self::UPLOAD_ADDS,$args) || $args[self::UPLOAD_ADDS] === "") {
206  $args = SpdxUtils::preWorkOnArgsFlp($args,self::UPLOAD_ADDS,self::OUTPUT_FORMAT_KEY);
207  }
208  }
209  return $args;
210  }
211 
216  function processUploadId($uploadId)
217  {
218  $args = $this->preWorkOnArgs($this->args);
219 
220  if (array_key_exists(self::OUTPUT_FORMAT_KEY,$args)) {
221  $possibleOutputFormat = trim($args[self::OUTPUT_FORMAT_KEY]);
222  if (in_array($possibleOutputFormat, explode(',',self::AVAILABLE_OUTPUT_FORMATS))) {
223  $this->outputFormat = $possibleOutputFormat;
224  }
225  }
226  $this->licenseMap = new LicenseMap($this->dbManager, $this->groupId, LicenseMap::REPORT, true);
227  $this->computeUri($uploadId);
228  $docLicense = $this->licenseDao->getLicenseByShortName(self::DATA_LICENSE);
229  $docLicenseId = $docLicense->getId() . "-" . md5($docLicense->getText());
230  $this->licensesInDocument[$docLicenseId] = (new SpdxLicenseInfo())
231  ->setLicenseObj($docLicense)
232  ->setListedLicense(true)
233  ->setCustomText(false)
234  ->setTextPrinted(true);
235  $packageNodes = $this->renderPackage($uploadId);
236  $additionalUploadIds = array_key_exists(self::UPLOAD_ADDS,$args) ? explode(',',$args[self::UPLOAD_ADDS]) : array();
237  $packageIds = array($uploadId);
238  foreach ($additionalUploadIds as $additionalId) {
239  $packageNodes .= $this->renderPackage($additionalId);
240  $packageIds[] = $additionalId;
241  }
242  $this->writeReport($packageNodes, $packageIds, $uploadId);
243  return true;
244  }
245 
251  protected function getTemplateFile($partname)
252  {
253  $prefix = $this->outputFormat . "-";
254  $postfix = ".twig";
255  switch ($this->outputFormat) {
256  case "spdx2":
257  $postfix = ".xml" . $postfix;
258  break;
259  case "spdx2csv":
260  case "spdx2tv":
261  break;
262  case "dep5":
263  $prefix .= "copyright-";
264  break;
265  case "spdx3jsonld":
266  break;
267  case "spdx3rdf":
268  $postfix = ".xml" . $postfix;
269  break;
270  case "spdx3json":
271  break;
272  case "spdx3tv":
273  break;
274  }
275  return $prefix . $partname . $postfix;
276  }
277 
285  protected function getFileBasename($packageName)
286  {
287  if ($this->filebasename == null) {
288  $fileName = strtoupper($this->outputFormat)."_".$packageName;
289  switch ($this->outputFormat) {
290  case "spdx2":
291  $fileName .= ".spdx.rdf";
292  break;
293  case "spdx2tv":
294  $fileName .= ".spdx";
295  break;
296  case "spdx2csv":
297  $fileName .= ".csv";
298  break;
299  case "dep5":
300  $fileName .= ".txt";
301  break;
302  case "spdx3jsonld":
303  $fileName = $fileName .".jsonld";
304  break;
305  case "spdx3json":
306  $fileName = $fileName .".json";
307  break;
308  case "spdx3rdf":
309  $fileName = $fileName .".spdx.rdf";
310  break;
311  case "spdx3tv":
312  $fileName = $fileName .".spdx";
313  break;
314  }
315  $this->filebasename = $fileName;
316  }
317  return $this->filebasename;
318  }
319 
325  protected function getFileName($packageName)
326  {
327  global $SysConf;
328  $fileBase = $SysConf['FOSSOLOGY']['path']."/report/";
329  return $fileBase. $this->getFileBasename($packageName);
330  }
331 
337  protected function getUri($packageName)
338  {
339  global $SysConf;
340  $url=$SysConf['SYSCONFIG']['FOSSologyURL'];
341  if (substr( $url, 0, 4 ) !== "http") {
342  $url="http://".$url;
343  }
344 
345  return rtrim($url, '/') . '/' . $this->getFileBasename($packageName);
346  }
347 
353  protected function renderPackage($uploadId)
354  {
355  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
356  $stateOsselot = $this->getSPDXReportConf($uploadId, 2);
357  $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId,$uploadTreeTableName);
358  $this->heartbeat(0);
359 
360  $filesWithLicenses = $this->reportutils
361  ->getFilesWithLicensesFromClearings($itemTreeBounds, $this->groupId,
362  $this, $this->licensesInDocument);
363  $this->heartbeat(0);
364 
365  $this->reportutils->addClearingStatus($filesWithLicenses,$itemTreeBounds, $this->groupId);
366  $this->heartbeat(0);
367 
368  $scannerIDs = $this->reportutils->addScannerResults($filesWithLicenses, $itemTreeBounds, $this->groupId, $this->licensesInDocument);
369  $licenseComment = "";
370  if (!empty($scannerIDs)) {
371  $licenseComment = $this->getLicenseComment($scannerIDs);
372  }
373  $this->heartbeat(0);
374 
375  $this->reportutils->addCopyrightResults($filesWithLicenses, $uploadId);
376  $this->heartbeat(0);
377 
378  $upload = $this->uploadDao->getUpload($uploadId);
379  $fileNodes = $this->generateFileNodes($filesWithLicenses, $upload->getTreeTableName(), $uploadId);
380 
381  $mainLicenseIds = $this->clearingDao->getMainLicenseIds($uploadId, $this->groupId);
382  $mainLicenses = array();
383  foreach ($mainLicenseIds as $licId) {
384  $reportedLicenseId = $this->licenseMap->getProjectedId($licId);
385  $mainLicense = $this->licenseDao->getLicenseById($reportedLicenseId, $this->groupId);
386  if ($mainLicense === null) {
387  error_log(
388  "spdx: Warning: main license ID {$reportedLicenseId} not found; skipping."
389  );
390  continue; // Skip this license and continue with the next one
391  }
392  $reportLicId = $mainLicense->getId() . "-" . md5($mainLicense->getText());
393  $mainLicenses[] = $reportLicId;
394  if (!array_key_exists($reportLicId, $this->licensesInDocument)) {
395  $listedLicense = stripos($mainLicense->getSpdxId(),
396  LicenseRef::SPDXREF_PREFIX) !== 0;
397  $this->licensesInDocument[$reportLicId] = (new SpdxLicenseInfo())
398  ->setLicenseObj($mainLicense)
399  ->setCustomText(false)
400  ->setListedLicense($listedLicense);
401  }
402  }
403  $mainLicenseString = [];
404  if ($this->outputFormat == "spdx2tv" ||
405  $this->outputFormat == "spdx2csv" ||
406  $this->outputFormat == "spdx3tv") {
407  foreach ($mainLicenses as $mainLicense) {
408  $shortName = $this->licensesInDocument[$mainLicense]
409  ->getLicenseObj()->getShortName();
410  if (StringOperation::stringStartsWith($shortName,
411  LicenseRef::SPDXREF_PREFIX)) {
412  $mainLicenseString[] = $shortName;
413  } else {
414  $mainLicenseString[] = $this->licensesInDocument[$mainLicense]
415  ->getLicenseObj()->getSpdxId();
416  }
417  }
418  if ($this->outputFormat == "spdx2tv") {
419  if ($stateOsselot) {
420  $mainLicenseString = SpdxUtils::removeEmptyLicenses($mainLicenseString);
421  foreach ($mainLicenseString as $i => $licId) {
422  if (StringOperation::stringStartsWith($licId, LicenseRef::SPDXREF_PREFIX)
423  || StringOperation::stringStartsWith($licId, "Dual-license")) {
424  continue;
425  }
426  $mainLicenseString[$i] = "LicenseRef-$licId";
427  }
428  }
429  }
430  $mainLicenseString = SpdxUtils::implodeLicenses(
431  SpdxUtils::removeEmptyLicenses($mainLicenseString));
432  }
433 
434  $hashes = $this->uploadDao->getUploadHashes($uploadId);
435 
436  $reportInfo = $this->uploadDao->getReportInfo($uploadId);
437  $componentId = $reportInfo['ri_component_id'];
438  $componentType = $reportInfo['ri_component_type'];
439  $componentVersion = $reportInfo['ri_version'];
440  $generalAssessment = $reportInfo['ri_general_assesment'];
441  $releaseDate = $reportInfo['ri_release_date'];
442  if ($componentId == "NA") {
443  $componentId = "";
444  }
445  if ($componentVersion == "NA") {
446  $componentVersion = "";
447  }
448  if ($generalAssessment == "NA") {
449  $generalAssessment = "";
450  }
451  if ($releaseDate == "NA") {
452  $releaseDate = "";
453  } else {
454  $timeStamp = strtotime($releaseDate);
455  if ($timeStamp != -1) {
456  $releaseDate = date("Y-m-d\\T00:00:00\\Z", $timeStamp);
457  } else {
458  $releaseDate = "";
459  }
460  }
461  if ($componentType == ComponentType::MAVEN) {
462  $componentType = "maven-central";
463  } elseif ($componentType == ComponentType::PACKAGEURL) {
464  $componentType = "purl";
465  } else {
466  if (!empty($componentType)) {
467  $componentType = ComponentType::TYPE_MAP[$componentType];
468  } else {
470  }
471  }
472  $obligations = $this->getObligations($uploadId, $this->groupId);
473 
474  return $this->renderString($this->getTemplateFile('package'), [
475  'packageId' => $uploadId,
476  'uri' => $this->uri,
477  'packageName' => $upload->getFilename(),
478  'packageVersion' => $componentVersion,
479  'releaseDate' => $releaseDate,
480  'generalAssessment' => $generalAssessment,
481  'uploadName' => $upload->getFilename(),
482  'componentType' => $componentType,
483  'componentId' => htmlspecialchars($componentId),
484  'sha1' => $hashes['sha1'],
485  'md5' => $hashes['md5'],
486  'sha256' => $hashes['sha256'],
487  'verificationCode' => $this->getVerificationCode($upload),
488  'mainLicenses' => $mainLicenses,
489  'mainLicenseString' => $mainLicenseString,
490  'licenseComments' => $licenseComment,
491  'fileNodes' => $fileNodes,
492  'obligations' => $obligations,
493  'licenseList' => $this->licensesInDocument,
494  'EnableOsselotExport' => $stateOsselot
495  ]);
496  }
497 
502  protected function getLicenseComment($scannerIds)
503  {
505  $func = function($scannerId) use ($agentDao)
506  {
507  return $agentDao->getAgentName($scannerId)." (".$agentDao->getAgentRev($scannerId).")";
508  };
509  $scannerNames = array_map($func, $scannerIds);
510  return "licenseInfoInFile determined by Scanners:\n - ".implode("\n - ",$scannerNames);
511  }
512 
521  protected function toLicensesWithFilesAdder(&$filesWithLicenses, $licenses, $copyrights, $file, $fullPath)
522  {
523  if (!array_key_exists($licenses, $filesWithLicenses)) {
524  $filesWithLicenses[$licenses]['files']=array();
525  $filesWithLicenses[$licenses]['copyrights']=array();
526  }
527  if (empty($copyrights)) {
528  $copyrights = array();
529  }
530  $filesWithLicenses[$licenses]['files'][$file] = $fullPath;
531  foreach ($copyrights as $copyright) {
532  if (!in_array($copyright, $filesWithLicenses[$licenses]['copyrights'])) {
533  $filesWithLicenses[$licenses]['copyrights'][] = $copyright;
534  }
535  }
536  }
537 
544  protected function toLicensesWithFiles(&$filesWithLicenses, $treeTableName)
545  {
546  $licensesWithFiles = array();
547  $treeDao = $this->container->get('dao.tree');
548  $filesProceeded = 0;
549  foreach ($filesWithLicenses as $fileId => $fileNode) {
550  $filesProceeded += 1;
551  if (($filesProceeded&2047)==0) {
552  $this->heartbeat(0);
553  }
554  $fullPath = $treeDao->getFullPath($fileId, $treeTableName, 0);
555  if (! empty($fileNode->getConcludedLicenses())) {
556  $licenses = [];
557  foreach ($fileNode->getConcludedLicenses() as $license) {
558  $licenses[] = $this->licensesInDocument[$license]
559  ->getLicenseObj()->getSpdxId();
560  }
561  $licenses = SpdxUtils::implodeLicenses(
562  SpdxUtils::removeEmptyLicenses(array_unique($licenses)));
563  $this->toLicensesWithFilesAdder($licensesWithFiles,
564  $licenses, $fileNode->getCopyrights(), $fileId, $fullPath);
565  } else {
566  if (! empty($fileNode->getScanners())) {
567  $implodedLicenses = [];
568  foreach ($fileNode->getScanners() as $license) {
569  $implodedLicenses[] = $this->licensesInDocument[$license]
570  ->getLicenseObj()->getSpdxId();
571  }
572  $implodedLicenses = SpdxUtils::implodeLicenses(
573  SpdxUtils::removeEmptyLicenses(array_unique($implodedLicenses)));
574  if ($fileNode->isCleared()) {
575  $msgLicense = "None (scanners found: " . $implodedLicenses . ")";
576  } else {
577  $msgLicense = "NoLicenseConcluded (scanners found: " . $implodedLicenses . ")";
578  }
579  } else {
580  if ($fileNode->isCleared()) {
581  $msgLicense = "None";
582  } else {
583  $msgLicense = "NoLicenseConcluded";
584  }
585  }
586  $this->toLicensesWithFilesAdder($licensesWithFiles, $msgLicense,
587  $fileNode->getCopyrights(), $fileId, $fullPath);
588  }
589  }
590  return $licensesWithFiles;
591  }
592 
597  protected function computeUri($uploadId)
598  {
599  $upload = $this->uploadDao->getUpload($uploadId);
600  $packageName = $upload->getFilename();
601 
602  $this->uri = $this->getUri($packageName);
603  $this->filename = $this->getFileName($packageName);
604  }
605 
612  protected function writeReport(&$packageNodes, $packageIds, $uploadId)
613  {
614  global $SysConf;
615  $stateOsselot = $this->getSPDXReportConf($uploadId, 2);
616  $fileBase = dirname($this->filename);
617 
618  if (!is_dir($fileBase)) {
619  mkdir($fileBase, 0777, true);
620  }
621  umask(0133);
622 
623  $organizationName = $SysConf['SYSCONFIG']["ReportHeaderText"] ?? 'FOSSology';
624  $version = $SysConf['BUILD']['VERSION'];
625 
626  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
627  $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId,$uploadTreeTableName);
628  $this->heartbeat(0);
629 
630  $filesWithLicenses = $this->reportutils
631  ->getFilesWithLicensesFromClearings($itemTreeBounds, $this->groupId,
632  $this, $this->licensesInDocument);
633  $this->heartbeat(0);
634  $upload = $this->uploadDao->getUpload($uploadId);
635  $this->generateFileNodes($filesWithLicenses, $upload->getTreeTableName(), $uploadId);
636  $this->declaredLicenseFileIds = array_unique(array_diff($this->declaredLicenseFileIds, $this->concludedLicenseFileIds));
637  $this->concludedLicenseFileIds = array_unique($this->concludedLicenseFileIds);
638  $message = $this->renderString($this->getTemplateFile('document'),array(
639  'documentName' => $fileBase,
640  'uri' => $this->uri,
641  'userName' => $this->container->get('dao.user')->getUserName($this->userId) . " (" . $this->container->get('dao.user')->getUserEmail($this->userId) . ")",
642  'organisation' => $organizationName,
643  'concludedLicenseFileIds'=>$this->concludedLicenseFileIds,
644  'declaredLicenseFileIds'=>$this->declaredLicenseFileIds,
645  'toolVersion' => 'fossology-' . $version,
646  'packageNodes' => $packageNodes,
647  'packageIds' => $packageIds,
648  'dataLicense' => $this->getSPDXDataLicense(),
649  'licenseList' => $this->licensesInDocument,
650  'EnableOsselotExport' => $stateOsselot,
651  )
652  );
653 
654  // To ensure the file is valid, replace any non-printable characters with a question mark.
655  // 'Non-printable' is ASCII < 0x20 (excluding \r, \n and tab) and 0x7F (delete).
656  $message = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/','?',$message);
657 
658  file_put_contents($this->filename, $message);
659  $this->updateReportTable($uploadId, $this->jobId, $this->filename);
660  }
661 
668  protected function updateReportTable($uploadId, $jobId, $fileName)
669  {
670  $this->reportutils->updateOrInsertReportgenEntry($uploadId, $jobId, $fileName);
671  }
672 
679  protected function renderString($templateName, $vars)
680  {
681  return $this->renderer->load($templateName)->render($vars);
682  }
683 
691  protected function generateFileNodes($filesWithLicenses, $treeTableName, $uploadId)
692  {
693  $this->deduplicateLicenseList();
694  if (strcmp($this->outputFormat, "dep5") !== 0) {
695  return $this->generateFileNodesByFiles($filesWithLicenses, $treeTableName, $uploadId);
696  } else {
697  return $this->generateFileNodesByLicenses($filesWithLicenses, $treeTableName);
698  }
699  }
700 
708  protected function generateFileNodesByFiles($filesWithLicenses, $treeTableName, $uploadId)
709  {
710  /* @var $treeDao TreeDao */
711  $treeDao = $this->container->get('dao.tree');
712  $filesProceeded = 0;
713  $lastValue = 0;
714  $content = '';
715  $textToBePrinted = [];
716  foreach ($filesWithLicenses as $fileId => $fileData) {
717  $filesProceeded += 1;
718  if (($filesProceeded & 2047) == 0) {
719  $this->heartbeat($filesProceeded - $lastValue);
720  $lastValue = $filesProceeded;
721  }
722  $hashes = $treeDao->getItemHashes($fileId);
723  $fileName = $treeDao->getFullPath($fileId, $treeTableName, 0);
724  $stateComment = $this->getSPDXReportConf($uploadId, 0);
725  $stateWoInfos = $this->getSPDXReportConf($uploadId, 1);
726  $stateOsselot = $this->getSPDXReportConf($uploadId, 2);
727  foreach ($fileData->getConcludedLicenses() as $license) {
728  $this->concludedLicenseFileIds[] = $fileId;
729  if (! $this->licensesInDocument[$license]->isTextPrinted()) {
730  $textToBePrinted[] = $license;
731  }
732  }
733  foreach ($fileData->getScanners() as $license) {
734  $this->declaredLicenseFileIds[] = $fileId;
735  if (! $this->licensesInDocument[$license]->isTextPrinted()) {
736  $textToBePrinted[] = $license;
737  }
738  }
739  $concludedLicensesString = [];
740  if ($this->outputFormat == "spdx2tv" ||
741  $this->outputFormat == "spdx2csv" ||
742  $this->outputFormat == "spdx3tv") {
743  foreach ($fileData->getConcludedLicenses() as $license) {
744  $shortName = $this->licensesInDocument[$license]
745  ->getLicenseObj()->getShortName();
746  if (StringOperation::stringStartsWith($shortName,
747  LicenseRef::SPDXREF_PREFIX)) {
748  $concludedLicensesString[] = $shortName;
749  } else {
750  $concludedLicensesString[] = $this->licensesInDocument[$license]
751  ->getLicenseObj()->getSpdxId();
752  }
753  }
754  if ($this->outputFormat == "spdx2tv") {
755  if ($stateOsselot) {
756  foreach ($concludedLicensesString as $j => $licId) {
757  if (StringOperation::stringStartsWith($licId, LicenseRef::SPDXREF_PREFIX)
758  || StringOperation::stringStartsWith($licId, "Dual-license")) {
759  continue;
760  }
761  $concludedLicensesString[$j] = "LicenseRef-$licId";
762  }
763  }
764  $concludedLicensesString = SpdxUtils::implodeLicenses(
765  SpdxUtils::removeEmptyLicenses($concludedLicensesString)
766  );
767  } else {
768  $concludedLicensesString = SpdxUtils::implodeLicenses(
769  SpdxUtils::removeEmptyLicenses($concludedLicensesString));
770  }
771  }
772  if (!$stateWoInfos ||
773  ($stateWoInfos && (!empty($fileData->getConcludedLicenses()) ||
774  !empty($fileData->getScanners()) || !empty($fileData->getCopyrights())))) {
775  $fileData->setAcknowledgements(
776  SpdxUtils::cleanTextArray($fileData->getAcknowledgements()));
777  $fileData->setComments(
778  SpdxUtils::cleanTextArray($fileData->getComments()));
779  $dataTemplate = array(
780  'fileId' => $fileId,
781  'sha1' => $hashes['sha1'],
782  'md5' => $hashes['md5'],
783  'sha256' => $hashes['sha256'],
784  'uri' => $this->uri,
785  'fileName' => $fileName,
786  'fileDirName' => dirname($fileName),
787  'fileBaseName' => basename($fileName),
788  'fileData' => $fileData,
789  'licenseList' => $this->licensesInDocument,
790  'concludedLicensesString' => $concludedLicensesString,
791  'licenseCommentState' => $stateComment,
792  'EnableOsselotExport' =>$stateOsselot,
793  );
794  $content .= $this->renderString($this->getTemplateFile('file'),
795  $dataTemplate);
796  }
797  foreach ($textToBePrinted as $license) {
798  $this->licensesInDocument[$license]->setTextPrinted(true);
799  }
800  }
801  $this->heartbeat($filesProceeded - $lastValue);
802  return $content;
803  }
804 
811  protected function generateFileNodesByLicenses($filesWithLicenses, $treeTableName)
812  {
813  $licensesWithFiles = $this->toLicensesWithFiles($filesWithLicenses, $treeTableName);
814 
815  $content = '';
816  $filesProceeded = 0;
817  $lastStep = 0;
818  $lastValue = 0;
819  foreach ($licensesWithFiles as $licenseId=>$entry) {
820  $filesProceeded += count($entry['files']);
821  if ($filesProceeded&(~2047) > $lastStep) {
822  $this->heartbeat($filesProceeded - $lastValue);
823  $lastStep = $filesProceeded&(~2047) + 2048;
824  $lastValue = $filesProceeded;
825  }
826 
827  $comment = "";
828  if (strrpos($licenseId, "NoLicenseConcluded (scanners found: ", -strlen($licenseId)) !== false) {
829  $comment = substr($licenseId,20,strlen($licenseId)-21);
830  $licenseId = "NoLicenseConcluded";
831  } elseif (strrpos($licenseId, "None (scanners found: ", -strlen($licenseId)) !== false) {
832  $comment = substr($licenseId,6,strlen($licenseId)-7);
833  $licenseId = "None";
834  }
835 
836  $content .= $this->renderString($this->getTemplateFile('file'),array(
837  'fileNames'=>$entry['files'],
838  'license'=>$licenseId,
839  'copyrights'=>$entry['copyrights'],
840  'comment'=>$comment));
841  }
842  $this->heartbeat($filesProceeded - $lastValue);
843  return $content;
844  }
845 
854  protected function getVerificationCode(Upload $upload)
855  {
856  $stmt = __METHOD__;
857  $param = array();
858  if ($upload->getTreeTableName()=='uploadtree_a') {
859  $sql = $upload->getTreeTableName().' WHERE upload_fk=$1 AND';
860  $param[] = $upload->getId();
861  } else {
862  $sql = $upload->getTreeTableName().' WHERE';
863  $stmt .= '.'.$upload->getTreeTableName();
864  }
865 
866  $sql = "SELECT STRING_AGG(lower_sha1,'') concat_sha1 FROM
867  (SELECT LOWER(pfile_sha1) lower_sha1 FROM pfile, $sql pfile_fk=pfile_pk AND parent IS NOT NULL ORDER BY pfile_sha1) templist";
868  $filelistPack = $this->dbManager->getSingleRow($sql,$param,$stmt);
869 
870  return sha1($filelistPack['concat_sha1']);
871  }
872 
880  protected function getSPDXReportConf($uploadId, $key)
881  {
882  $sql = "SELECT ri_spdx_selection FROM report_info WHERE upload_fk = $1";
883  $getCommentState = $this->dbManager->getSingleRow($sql, array($uploadId), __METHOD__.'.SPDX_license_comment');
884  if (!empty($getCommentState['ri_spdx_selection'])) {
885  $getCommentStateSingle = explode(',', $getCommentState['ri_spdx_selection']);
886  if ($getCommentStateSingle[$key] === "checked") {
887  return true;
888  }
889  }
890  return false;
891  }
898  private function getObligations(int $uploadId, int $groupId): array
899  {
900  $licenses = $this->licenseClearedGetter->getCleared($uploadId, $this,
901  $groupId, true, "license", false);
902  $this->heartbeat(0);
903  $licensesMain = $this->licenseMainGetter->getCleared($uploadId, $this,
904  $groupId, true, null, false);
905  $this->heartbeat(0);
906  list($obligations, $_) = $this->obligationsGetter->getObligations(
907  $licenses['statements'], $licensesMain['statements'], $uploadId,
908  $groupId);
909  if (empty($obligations)) {
910  return [];
911  } else {
912  return array_column($obligations, "text");
913  }
914  }
915 
920  protected function getSPDXDataLicense()
921  {
922  $dataLic = $this->licenseDao->getLicenseByShortName(self::DATA_LICENSE);
923  return $dataLic->getId() . "-" . md5($dataLic->getText());
924  }
925 
937  private function deduplicateLicenseList()
938  {
939  $localList = array_values($this->licensesInDocument);
940  usort($localList,
941  function(SpdxLicenseInfo $a, SpdxLicenseInfo $b) {
942  return strcmp(
943  $a->getLicenseObj()->getSpdxId() . $a->getLicenseObj()->getShortName(),
944  $b->getLicenseObj()->getSpdxId() . $b->getLicenseObj()->getShortName());
945  }
946  );
947  for ($i = 0; $i < count($localList) - 1; $i++) {
948  if ((! $localList[$i]->isCustomText() && ! $localList[$i + 1]->isCustomText()) &&
949  $localList[$i]->getLicenseObj()->getSpdxId() ===
950  $localList[$i + 1]->getLicenseObj()->getSpdxId()) {
951  $newShortName = $localList[$i + 1]->getLicenseObj()->getShortName();
953  $localList[$i + 1]->getLicenseObj()->getShortName(),
954  LicenseRef::SPDXREF_PREFIX)) {
955  $newShortName = LicenseRef::SPDXREF_PREFIX .
956  $localList[$i + 1]->getLicenseObj()->getShortName();
957  $newShortName = preg_replace('/\+$/', '-or-later', $newShortName);
958  }
959  $md5 = md5($localList[$i + 1]->getLicenseObj()->getText());
960  $reportedLicenseShortname = "$newShortName-$md5";
961  $licIndex = $localList[$i + 1]->getLicenseObj()->getId() . "-$md5";
962  $oldLicObj = $this->licensesInDocument[$licIndex]->getLicenseObj();
963  $this->licensesInDocument[$licIndex]->setLicenseObj(
964  new License($oldLicObj->getId(), $reportedLicenseShortname,
965  $oldLicObj->getFullName(), $oldLicObj->getRisk(),
966  $oldLicObj->getText(), $oldLicObj->getUrl(),
967  $oldLicObj->getDetectorType(), $oldLicObj->getSpdxId()));
968  }
969  }
970  }
971 }
972 
973 $agent = new SpdxAgent();
974 $agent->scheduler_connect();
975 $agent->run_scheduler_event_loop();
976 $agent->scheduler_disconnect(0);
Structure of an Agent with all required parameters.
Definition: Agent.php:41
heartbeat($newProcessed)
Send hear beat to the scheduler.
Definition: Agent.php:203
Contains the constants and helpers for authentication of user.
Definition: Auth.php:24
Wrapper class for license map.
Definition: LicenseMap.php:19
static stringStartsWith($haystack, $needle)
SPDX2 agent.
Definition: spdx.php:77
const DEFAULT_OUTPUT_FORMAT
Default output format.
Definition: spdx.php:80
getLicenseComment($scannerIds)
Definition: spdx.php:502
getFileName($packageName)
Get absolute path for report.
Definition: spdx.php:325
getVerificationCode(Upload $upload)
Get a unique identifier for a given upload.
Definition: spdx.php:854
getTemplateFile($partname)
Get TWIG template file based on output format.
Definition: spdx.php:251
const UPLOAD_ADDS
Argument for additional uploads.
Definition: spdx.php:82
getObligations(int $uploadId, int $groupId)
Definition: spdx.php:898
processUploadId($uploadId)
Given an upload ID, process the items in it.
Definition: spdx.php:216
const DATA_LICENSE
Data license for SPDX reports.
Definition: spdx.php:83
updateReportTable($uploadId, $jobId, $fileName)
Update the reportgen table with new report path.
Definition: spdx.php:668
preWorkOnArgs($args)
Parse arguments.
Definition: spdx.php:198
renderString($templateName, $vars)
Render a twig template.
Definition: spdx.php:679
const AVAILABLE_OUTPUT_FORMATS
Output formats available.
Definition: spdx.php:81
renderPackage($uploadId)
Given an upload id, render the report string.
Definition: spdx.php:353
getFileBasename($packageName)
Generate report basename based on upload name.
Definition: spdx.php:285
generateFileNodesByLicenses($filesWithLicenses, $treeTableName)
For each file, generate the nodes by licenses.
Definition: spdx.php:811
toLicensesWithFiles(&$filesWithLicenses, $treeTableName)
Map findings to the files.
Definition: spdx.php:544
generateFileNodes($filesWithLicenses, $treeTableName, $uploadId)
Generate report nodes for files.
Definition: spdx.php:691
getSPDXReportConf($uploadId, $key)
Get spdx license comment state for a given upload.
Definition: spdx.php:880
toLicensesWithFilesAdder(&$filesWithLicenses, $licenses, $copyrights, $file, $fullPath)
Map licenses, copyrights, files and full path to filesWithLicenses array.
Definition: spdx.php:521
generateFileNodesByFiles($filesWithLicenses, $treeTableName, $uploadId)
For each file, generate the nodes by files.
Definition: spdx.php:708
writeReport(&$packageNodes, $packageIds, $uploadId)
Write the report the file and update report table.
Definition: spdx.php:612
computeUri($uploadId)
For a given upload, compute the URI and filename for the report.
Definition: spdx.php:597
const OUTPUT_FORMAT_KEY
Argument key for output format.
Definition: spdx.php:79
getUri($packageName)
Get the URI for the given package.
Definition: spdx.php:337
deduplicateLicenseList()
De-duplicate license list by comparing licenses with the same SPDX ID.
Definition: spdx.php:937
static preWorkOnArgsFlp($args, $key1, $key2)
For a given set of arguments assign $args[$key1] and $args[$key2].
Definition: spdxutils.php:29
static implodeLicenses($licenses)
Implode licenses with "AND" or "OR".
Definition: spdxutils.php:97
static removeEmptyLicenses($licenses)
Definition: spdxutils.php:148
static cleanTextArray($texts)
Definition: spdxutils.php:124
char * trim(char *ptext)
Trimming whitespace.
Definition: fossconfig.c:690
int jobId
The id of the job.
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16
FUNCTION char * strtoupper(char *s)
Helper function to upper case a string.
Definition: utils.c:39
Namespace used by SPDX2 agent.
list_t type structure used to keep various lists. (e.g. there are multiple lists).
Definition: nomos.h:308