FOSSology  4.4.0
Open Source License Compliance by Open Source Software
exportLicenseRefUsingSPDX.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2019,2021,2022 Siemens AG
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 
9 
18 {
23  private $mapArrayData = array(
24  'licenses' => array('licenseId', 'licenseText', 'name'),
25  'exceptions' => array('licenseExceptionId', 'licenseExceptionText', 'name')
26  );
27 
28 
29  function startProcessingLicenseData()
30  {
31  global $argv;
32  $updateWithNew = '';
33  $updateExisting = '';
34  $addNewLicense = '';
35  $deleteDeprecated = false;
36  $newLicenseRefData = array();
37  $showUsage = '';
38  $scanList = array(
39  'licenses' => 'https://spdx.org/licenses/licenses.json',
40  'exceptions' => 'https://spdx.org/licenses/exceptions.json'
41  );
42  $usage = "Usage: " . basename($argv[0]) . " [options]
43 
44  Create new licenseref.json file. Options are:
45  -E Update all existing licenses and also add new licenses.
46  (NOTE: there may be failure of test cases)
47 
48  -e Only update existing licenses.
49  (NOTE: there may be failure of test cases)
50 
51  -n Only add new licenses.
52 
53  -d Delete deprecated licenses.
54 
55  --type Usually licenses/exceptions (optional)
56  (ex: --type 'licenses')
57 
58  --url From where you want to download (optional)
59  (ex: --url 'https://spdx.org/licenses/licenses.json')
60 
61  Additional note:
62  (if --type and --url is empty then the script will automatically download the from below)
63  For type 'licenses' URL is : $scanList[licenses]
64 
65  For type 'exceptions' URL is : $scanList[exceptions]";
66 
67  $options = getopt("hcEend", array("type:", "url:"));
68  /* get type and url if exists, if not set them to empty */
69  $type = array_key_exists("type", $options) ? $options["type"] : '';
70  $URL = array_key_exists("url", $options) ? $options["url"] : '';
71  foreach ($options as $option => $optVal) {
72  switch ($option) {
73  case 'c': /* used by fo_wrapper */
74  break;
75  case 'E': /* Update all existing licenses and also add new licenses */
76  $updateWithNew = $option;
77  break;
78  case 'e': /* Only update existing licenses */
79  $updateExisting = $option;
80  break;
81  case 'n': /* only add new licenses */
82  $addNewLicense = $option;
83  break;
84  case 'd': /* Delete deprecated licenses */
85  $deleteDeprecated = true;
86  break;
87  case 'h': /* help */
88  $showUsage = true;
89  break;
90  }
91  }
92 
93  if ($showUsage) {
94  print "$usage\n";
95  exit;
96  }
97 
98  if (!empty($updateWithNew) || !empty($updateExisting) || !empty($addNewLicense)) {
99  if (!empty($type) && !empty($URL)) {
100  $newLicenseRefData = $this->getListSPDX($type, $URL, $updateWithNew, $updateExisting, $addNewLicense,
101  $newLicenseRefData, $deleteDeprecated);
102  } else if (!empty($type) && empty($URL)) {
103  echo "Notice: --url cannot be empty if --type is provided \n";
104  } else if (empty($type) && !empty($URL)) {
105  echo "Notice: --type cannot be empty if --url is provided \n";
106  } else {
107  foreach ($scanList as $type => $URL) {
108  $newLicenseRefData = $this->getListSPDX($type, $URL, $updateWithNew, $updateExisting, $addNewLicense,
109  $newLicenseRefData, $deleteDeprecated);
110  }
111  }
112  $newFileName = "licenseRefNew.json";
113  if (file_exists($newFileName)) {
114  unlink($newFileName);
115  }
116  $this->sanitizeRefData($newLicenseRefData);
117  $file = fopen($newFileName, 'w+');
118  file_put_contents($newFileName, json_encode($newLicenseRefData, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES));
119  fclose($file);
120  echo "\n\n INFO: new $newFileName file created \n\n";
121  } else {
122  echo "\nINVALID OPTION PROVIDED\n\n";
123  print "$usage\n";
124  exit;
125  }
126  }
127 
138  function getListSPDX($type, $URL, $updateWithNew, $updateExisting, $addNewLicense, $existingLicenseRefData,
139  $deleteDeprecated)
140  {
141  global $LIBEXECDIR;
142 
143  if (!is_dir($LIBEXECDIR)) {
144  print "FATAL: Directory '$LIBEXECDIR' does not exist.\n";
145  return (1);
146  }
147 
148  $dir = opendir($LIBEXECDIR);
149  if (!$dir) {
150  print "FATAL: Unable to access '$LIBEXECDIR'.\n";
151  return (1);
152  }
153  /* check if licenseref.json exists */
154  $fileName = "$LIBEXECDIR/licenseRef.json";
155  if (!file_exists($fileName)) {
156  print "FATAL: File '$fileName' does not exist.\n";
157  return (1);
158  }
159 
160  if (empty($existingLicenseRefData)) {
161  echo "INFO: get existing licenseRef.json from $LIBEXECDIR\n";
162  $getExistingLicenseRefData = file_get_contents("$fileName");
163  /* dump all the data from licenseRef.json file to an array */
164  $existingLicenseRefData = (array) json_decode($getExistingLicenseRefData, true);
165  }
166  /* get license list and each license's URL */
167  $getList = json_decode(file_get_contents($URL));
168  foreach ($getList->$type as $listValue) {
169  /* get current license data from given URL */
170  if (strstr($URL, "spdx.org") !== false) {
171  // If fetching exceptions from spdx, fix the detailsUrl
172  if (substr_compare($listValue->detailsUrl, ".html", -5) === 0) {
173  $baseUrl = str_replace("exceptions.json", "", $URL);
174  $listValue->detailsUrl = $baseUrl . str_replace("./", "", $listValue->reference);
175  }
176  }
177  $getCurrentData = file_get_contents($listValue->detailsUrl);
178  $getCurrentData = (array) json_decode($getCurrentData, true);
179  echo "INFO: search for license " . $getCurrentData[$this->mapArrayData[$type][0]] . "\n";
180  /* check if the licenseid of the current license exists in old license data */
181  $licenseIdCheck = array_search($getCurrentData[$this->mapArrayData[$type][0]],
182  array_column($existingLicenseRefData, 'rf_shortname'));
183  $currentText = $this->replaceUnicode($getCurrentData[$this->mapArrayData[$type][1]]);
184  $textCheck = array_search($currentText, array_column($existingLicenseRefData, 'rf_text'));
185  if ($deleteDeprecated && $listValue->isDeprecatedLicenseId && (
186  is_numeric($licenseIdCheck) &&
187  (!empty($updateWithNew) || !empty($updateExisting)))) {
188  // Existing deprecated license, delete it
189  echo "INFO: removing deprecated license " .
190  $getCurrentData[$this->mapArrayData[$type][0]] . "\n";
191  unset($existingLicenseRefData[$licenseIdCheck]);
192  $existingLicenseRefData = array_values($existingLicenseRefData);
193  continue;
194  } elseif ($listValue->isDeprecatedLicenseId) {
195  continue;
196  }
197  if (is_numeric($licenseIdCheck) &&
198  (!empty($updateWithNew) || !empty($updateExisting))) {
199  // License exists, just remove old fields
200  if (array_key_exists('rf_spdx_compatible',
201  $existingLicenseRefData[$licenseIdCheck])) {
202  unset($existingLicenseRefData[$licenseIdCheck]['rf_spdx_compatible']);
203  }
204  }
205  if (
206  is_numeric($licenseIdCheck) &&
207  !is_numeric($textCheck) &&
208  (!empty($updateWithNew) ||
209  !empty($updateExisting)
210  )
211  ) {
212  $existingLicenseRefData[$licenseIdCheck]['rf_fullname'] = $getCurrentData[$this->mapArrayData[$type][2]];
213  $existingLicenseRefData[$licenseIdCheck]['rf_text'] = $getCurrentData[$this->mapArrayData[$type][1]];
214  $existingLicenseRefData[$licenseIdCheck]['rf_url'] = $getCurrentData['seeAlso'][0];
215  $existingLicenseRefData[$licenseIdCheck]['rf_notes'] = (array_key_exists("licenseComments", $getCurrentData) ? $getCurrentData['licenseComments'] : $existingLicenseRefData[$licenseIdCheck]['rf_notes']);
216  echo "INFO: license " . $getCurrentData[$this->mapArrayData[$type][0]] . " updated\n\n";
217  }
218  if (
219  !is_numeric($licenseIdCheck) &&
220  !is_numeric($textCheck) &&
221  (!empty($updateWithNew) ||
222  !empty($addNewLicense)
223  )
224  ) {
225  $existingLicenseRefData[] = array(
226  'rf_shortname' => $getCurrentData[$this->mapArrayData[$type][0]],
227  'rf_text' => $getCurrentData[$this->mapArrayData[$type][1]],
228  'rf_url' => $getCurrentData['seeAlso'][0],
229  'rf_add_date' => null,
230  'rf_copyleft' => null,
231  'rf_OSIapproved' => null,
232  'rf_fullname' => $getCurrentData[$this->mapArrayData[$type][2]],
233  'rf_FSFfree' => null,
234  'rf_GPLv2compatible' => null,
235  'rf_GPLv3compatible' => null,
236  'rf_notes' => (array_key_exists("licenseComments", $getCurrentData) ? $getCurrentData['licenseComments'] : null),
237  'rf_Fedora' => null,
238  'marydone' => "f",
239  'rf_active' => "t",
240  'rf_text_updatable' => "f",
241  'rf_detector_type' => 1,
242  'rf_source' => null,
243  'rf_risk' => null,
244  'rf_spdx_compatible' => $listValue->isDeprecatedLicenseId == false,
245  'rf_flag' => "1",
246  );
247  echo "INFO: new license " . $getCurrentData[$this->mapArrayData[$type][0]] . " added\n\n";
248  }
249  }
250  return array_values($existingLicenseRefData);
251  }
252 
259  private function replaceUnicode($text)
260  {
261  if ($text === null) {
262  return null;
263  }
264  $search = [
265  "\u{00a0}", // no break space
266  "\u{2018}", // Left single quote
267  "\u{2019}", // Right single quote
268  "\u{201c}", // Left double quote
269  "\u{201d}", // Right double quote
270  "\u{2013}", // em dash
271  "\u{2028}", // line separator
272  ];
273 
274  $replace = [
275  " ",
276  "'",
277  "'",
278  '"',
279  '"',
280  "-",
281  "\n",
282  ];
283 
284  return StringOperation::replaceUnicodeControlChar(str_replace($search,
285  $replace, $text));
286  }
287 
293  private function sanitizeRefData(&$newLicenseRefData)
294  {
295  for ($i = 0; $i < count($newLicenseRefData); $i++) {
296  $newLicenseRefData[$i]["rf_fullname"] = $this->replaceUnicode($newLicenseRefData[$i]["rf_fullname"]);
297  $newLicenseRefData[$i]["rf_text"] = $this->replaceUnicode($newLicenseRefData[$i]["rf_text"]);
298  $newLicenseRefData[$i]["rf_notes"] = $this->replaceUnicode($newLicenseRefData[$i]["rf_notes"]);
299  }
300  }
301 }
302 $obj = new exportLicenseRef();
303 $obj->startProcessingLicenseData();
sanitizeRefData(&$newLicenseRefData)
getListSPDX($type, $URL, $updateWithNew, $updateExisting, $addNewLicense, $existingLicenseRefData, $deleteDeprecated)
get SPDX license or exception list and update licenseref.json