organic: Add extended API
This commit is contained in:
+45
-185
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
require '.php/pdf.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'POST' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
||||
header('Status: 405');
|
||||
header('Content-Length: 0');
|
||||
@@ -17,25 +19,6 @@ if ($info !== '') {
|
||||
$url = isset($_GET['url']) ? str_replace(' ', '+', $_GET['url']) : null;
|
||||
$format = $_GET['format'] ?? 'json';
|
||||
|
||||
function get_address($array, $from, $to): array {
|
||||
$address = [];
|
||||
$postalCode = [];
|
||||
$city = [];
|
||||
for ($i = $to; $i >= $from; $i--) {
|
||||
$el = $array[$i];
|
||||
if (sizeof($postalCode) > 0) {
|
||||
if (sizeof($address) === 0) $el = rtrim($el, ", \n\r\t\v\0");
|
||||
if (strlen($el) === 0) continue;
|
||||
array_unshift($address, $el);
|
||||
} else if (preg_match("/^[A-Z0-9.\-]{3,},?$/", $el)) {
|
||||
array_unshift($postalCode, trim($el, ", \n\r\t\v\0"));
|
||||
} else {
|
||||
array_unshift($city, $el);
|
||||
}
|
||||
}
|
||||
return [implode(' ', $address), implode(' ', $postalCode), implode(' ', $city)];
|
||||
}
|
||||
|
||||
function jenc($data): string {
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
@@ -47,7 +30,9 @@ if (!$file || !$headerfile) {
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
$filename = stream_get_meta_data($file)['uri'];
|
||||
$cacheFile = null;
|
||||
$tmpfilename = stream_get_meta_data($file)['uri'];
|
||||
$filename = $tmpfilename;
|
||||
$headerfilename = stream_get_meta_data($headerfile)['uri'];
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$stdin = fopen("php://input", "rb");
|
||||
@@ -58,13 +43,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
fclose($stdin);
|
||||
} else {
|
||||
if (exec("curl -s -D " . escapeshellarg($headerfilename) . " -o " . escapeshellarg($filename) . " " . escapeshellarg($url)) === false) {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
if ($cache = fopen('certificates/.cache.csv', 'r')) {
|
||||
while (($line = fgets($cache)) !== false) {
|
||||
$parts = explode(';', trim($line), 3);
|
||||
$timestamp = intval($parts[0]);
|
||||
if ($parts[2] !== $url) continue;
|
||||
$cacheFile = 'certificates/' . $parts[1] . '.pdf';
|
||||
break;
|
||||
}
|
||||
fclose($cache);
|
||||
}
|
||||
|
||||
if ($cacheFile !== null) {
|
||||
$filename = $cacheFile;
|
||||
} else {
|
||||
if (exec("curl -sk -D " . escapeshellarg($headerfilename) . " -o " . escapeshellarg($filename) . " " . escapeshellarg($url)) === false) {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$timestamp = time();
|
||||
|
||||
if ($format === 'text') {
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
passthru("pdftotext -raw " . escapeshellarg($filename) . " -");
|
||||
@@ -73,176 +75,34 @@ if ($format === 'text') {
|
||||
passthru("pdfsig " . escapeshellarg($filename));
|
||||
} else if ($format === 'json') {
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
if (exec("pdftotext -raw " . escapeshellarg($filename) . " -", $text) === false) {
|
||||
|
||||
if (($cert = parse_pdf($filename, true)) === null) {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
$text = implode("\n", $text);
|
||||
exec("pdfsig " . escapeshellarg($filename), $sig);
|
||||
$sig = implode("\n", $sig);
|
||||
$certType = $cert['type'];
|
||||
$certId = $cert['id'];
|
||||
|
||||
$r = preg_match('@([a-z]{2}) (https://webgate\.ec\.europa\.eu/tracesnt/directory/publication/organic-operator/(.*?)\.pdf) (\d+) / (\d+)@', $text, $matches);
|
||||
if ($r === 1) {
|
||||
// TRACES certificate
|
||||
|
||||
$data = [];
|
||||
$parts = preg_split('@\n(I+\.\d+) ([^\n]*)@', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$status = str_replace("\n", '', $parts[0]);
|
||||
for ($i = 3; $i < sizeof($parts); $i += 3) {
|
||||
$data[$parts[$i - 2]] = trim($parts[$i]);
|
||||
if ($certType === 'traces') {
|
||||
if ($certId !== null && $url !== null && $cacheFile === null) {
|
||||
copy($filename, "certificates/$certId.pdf");
|
||||
file_put_contents('certificates/.cache.csv', "$timestamp;$certId;$url\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
$lang = $matches[1];
|
||||
$splitAddr = [
|
||||
'de' => 'Adresse',
|
||||
'en' => 'Address',
|
||||
][$lang];
|
||||
$splitCountry = [
|
||||
'de' => 'Land',
|
||||
'en' => 'Country',
|
||||
][$lang];
|
||||
$statusMap = [
|
||||
'de' => [
|
||||
'AUSGESTELLT' => 'issued',
|
||||
],
|
||||
'en' => [
|
||||
'ISSUED' => 'issued',
|
||||
]
|
||||
][$lang];
|
||||
$activityMap = [
|
||||
'de' => [
|
||||
'Aufbereitung' => 'preparation',
|
||||
'Ausfuhr' => 'export',
|
||||
'Einfuhr' => 'import',
|
||||
'Lagerung' => 'storing',
|
||||
'Produktion' => 'production',
|
||||
'Vertrieb' => 'distribution',
|
||||
'Vertrieb/Inverkehrbringen' => 'distribution_placing_on_the_market',
|
||||
],
|
||||
'en' => [
|
||||
'Distribution' => 'distribution',
|
||||
'Distribution/Placing on the market' => 'distribution_placing_on_the_market',
|
||||
'Export' => 'export',
|
||||
'Import' => 'import',
|
||||
'Preparation' => 'preparation',
|
||||
'Production' => 'production',
|
||||
'Storing' => 'storing',
|
||||
],
|
||||
][$lang];
|
||||
|
||||
$certUrl = $matches[2];
|
||||
$certId = $matches[3];
|
||||
$authorityId = explode('.', $certId)[0];
|
||||
$operatorId = explode('.', $certId)[1];
|
||||
$operator = preg_split('@\s+@', trim($data['I.3']));
|
||||
$p1 = array_search($splitAddr, $operator);
|
||||
$p2 = array_search($splitCountry, $operator);
|
||||
$operatorName = trim(implode(' ', array_filter($operator, fn($k,$i) => $i > 0 && $i < $p1, ARRAY_FILTER_USE_BOTH)), ', ');
|
||||
[$opAddr, $opPostal, $opCity] = get_address($operator, $p1 + 1, $p2 - 1);
|
||||
|
||||
$authority = preg_split('@\s+@', trim($data['I.4']));
|
||||
$until = array_search("($authorityId)", $authority);
|
||||
$p1 = array_search($splitAddr, $authority);
|
||||
$p2 = array_search($splitCountry, $authority);
|
||||
$authorityName = implode(' ', array_filter($authority, fn($k,$i) => $i > 0 && $i < $p1 - 1 && ($i !== $p1 - 2 || !str_starts_with($k, '(')), ARRAY_FILTER_USE_BOTH));
|
||||
[$aAddr, $aPostal, $aCity] = get_address($authority, $p1 + 1, $p2 - 1);
|
||||
|
||||
$activities = [];
|
||||
foreach (explode("\n", $data['I.5']) as $a) {
|
||||
$activities[] = $activityMap[trim($a, '• ')];
|
||||
} else if ($certType !== 'unknown') {
|
||||
if ($certId !== null && $url !== null && $cacheFile === null) {
|
||||
copy($filename, "certificates/$certId.appendix.pdf");
|
||||
file_put_contents('certificates/.cache.csv', "$timestamp;$certId.appendix;$url\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
preg_match_all('/\([a-g]\)/', $data['I.6'], $matches, PREG_SET_ORDER);
|
||||
$products = [];
|
||||
foreach ($matches as $m) {
|
||||
$products[] = $m[0];
|
||||
}
|
||||
|
||||
preg_match_all('@\d+/\d+/\d+@', $data['I.8'], $matches, PREG_SET_ORDER);
|
||||
$valid1 = implode('-', array_reverse(explode('/', $matches[0][0])));
|
||||
$valid2 = implode('-', array_reverse(explode('/', $matches[1][0])));
|
||||
|
||||
$sigs = [];
|
||||
foreach (array_slice(explode("\nSignature #", $sig), 1) as $s) {
|
||||
$sData = [];
|
||||
$sData2 = [];
|
||||
preg_match_all('/\n {2}- (([^:\n]*): )?([^\n]*)/', $s, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $m) {
|
||||
if (strlen($m[2]) === 0) {
|
||||
$sData2[] = $m[3];
|
||||
} else {
|
||||
$sData[$m[2]] = $m[3];
|
||||
}
|
||||
}
|
||||
$sigs[] = [
|
||||
'signerCommonName' => $sData['Signer Certificate Common Name'],
|
||||
'valid' => $sData['Signature Validation'] === 'Signature is Valid.',
|
||||
'trusted' => $sData['Certificate Validation'] === 'Certificate is Trusted.',
|
||||
'totalDocument' => in_array('Total document signed', $sData2),
|
||||
'timestamp' => gmdate('Y-m-d\TH:i:s\Z', strtotime($sData['Signing Time'])),
|
||||
'type' => $sData['Signature Type'],
|
||||
'hashAlgorithm' => $sData['Signing Hash Algorithm'],
|
||||
'signerDistinguishedName' => $sData['Signer full Distinguished Name'],
|
||||
'fieldName' => $sData['Signature Field Name'],
|
||||
];
|
||||
}
|
||||
|
||||
echo "{\"type\":\"traces\",\"lang\":\"$lang\",\"id\":\"$certId\",\"status\":\"$statusMap[$status]\"";
|
||||
echo ",\n \"operator\":{\"id\":" . jenc($operatorId).
|
||||
',"groupOfOperators":' . jenc(!str_starts_with($data['I.2'], '☑')) .
|
||||
',"name":' . jenc($operatorName) .
|
||||
',"address":' . jenc($opAddr) .
|
||||
',"postalCode":' . jenc($opPostal) .
|
||||
',"city":' . jenc($opCity) .
|
||||
',"countryCode":' . jenc($operator[sizeof($operator) - 1]) .
|
||||
"},\n \"authority\":{\"id\":" . jenc($authorityId) .
|
||||
',"name":' . jenc($authorityName) .
|
||||
',"address":' . jenc($aAddr) .
|
||||
',"postalCode":' . jenc($aPostal) .
|
||||
',"city":' . jenc($aCity) .
|
||||
',"countryCode":' . jenc($authority[sizeof($authority) - 1]) .
|
||||
"},\n \"activities\":" . jenc($activities) .
|
||||
",\n \"productCategories\":" . jenc($products) .
|
||||
",\n \"validFrom\":" . jenc($valid1) .
|
||||
',"validTo":' . jenc($valid2) .
|
||||
",\n \"url\":\"$certUrl\"" .
|
||||
",\n \"digitalSignatures\":" . jenc($sigs) .
|
||||
"\n}\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (preg_match('/AT-BIO-[0-9]{3}/', $text, $matches) === 1) {
|
||||
$authorityId = $matches[0];
|
||||
$certId = null;
|
||||
$certNr = null;
|
||||
if (preg_match("/$authorityId\.040-[0-9]{7}\.[0-9]{4}\.[0-9]{3}/", $text, $matches) === 1)
|
||||
$certId = $matches[0];
|
||||
if (preg_match_all("/\b[0-9]+([._-])[0-9]+\g{-1}[0-9]+\b/", $text, $matches, PREG_SET_ORDER) !== false) {
|
||||
foreach ($matches as $m) {
|
||||
if (strlen($m[0]) > 10 && !str_ends_with($certId, $m[0]))
|
||||
$certNr = $m[0];
|
||||
}
|
||||
}
|
||||
$operator = ['lfbisNr' => null];
|
||||
if ($authorityId === 'AT-BIO-301') {
|
||||
// TODO
|
||||
} else if ($authorityId === 'AT-BIO-302') {
|
||||
if (preg_match("/^lfbis[^0-9]*([0-9]{7})$/im", $text, $matches) === 1)
|
||||
$operator['lfbisNr'] = $matches[1];
|
||||
} else if ($authorityId === 'AT-BIO-401') {
|
||||
// TODO
|
||||
} else if ($authorityId === 'AT-BIO-402') {
|
||||
// TODO
|
||||
} else if ($authorityId === 'AT-BIO-903') {
|
||||
// TODO
|
||||
}
|
||||
echo "{\"type\":\"$authorityId\",\"lang\":\"de\",\"id\":" . jenc($certId) . ",\"nr\":" . jenc($certNr);
|
||||
echo ",\n \"operator\":" . jenc($operator) . ",\n \"authority\":{\"id\":" . jenc($authorityId) . "}}\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
echo "{\"type\":\"unknown\"}\n";
|
||||
echo jenc($cert);
|
||||
exit;
|
||||
} else if ($cacheFile === $filename) {
|
||||
header('Content-Type: application/pdf');
|
||||
header('Content-Length: ' . filesize($filename));
|
||||
header('Content-Disposition: inline; filename="' . basename($filename) . '"');
|
||||
readfile($filename);
|
||||
} else {
|
||||
$headers = [];
|
||||
$status_code = null;
|
||||
|
||||
Reference in New Issue
Block a user