organic: Add extended API
This commit is contained in:
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
|
||||
require "../.php/pdf.php";
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
||||
header('Status: 405');
|
||||
header('Content-Length: 56');
|
||||
header('Allow: GET, HEAD');
|
||||
echo "{\"error\":\"method not allowed\",\"allow\":[\"GET\",\"HEAD\"]}\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
function jenc($data): string {
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
function jget($url): array | null {
|
||||
$s = curl_init($url);
|
||||
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
|
||||
if (($json = curl_exec($s)) === false) {
|
||||
return null;
|
||||
}
|
||||
return json_decode($json, true);
|
||||
}
|
||||
|
||||
function pdf_fetch($url): array | null {
|
||||
$s = curl_init("https://elwig.at/organic/pdf?format=json&url=" . urlencode($url));
|
||||
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
|
||||
if (($json = curl_exec($s)) === false) {
|
||||
return null;
|
||||
}
|
||||
return json_decode($json, true);
|
||||
}
|
||||
|
||||
function update_local(string $ooId, array $new): bool {
|
||||
$existed = file_exists(".ids/$ooId.txt");
|
||||
if (!($file = fopen(".ids/$ooId.txt", 'c+')))
|
||||
return !$existed;
|
||||
$data = [];
|
||||
while (($line = fgets($file)) !== false) {
|
||||
[$k,$v] = explode(':', trim($line), 2);
|
||||
$data[$k] = $v;
|
||||
}
|
||||
foreach ($new as $k => $v) {
|
||||
if ($v !== null)
|
||||
$data[$k] = $v;
|
||||
}
|
||||
fseek($file, 0);
|
||||
ftruncate($file, 0);
|
||||
foreach ($data as $k => $v) {
|
||||
fwrite($file, "$k:$v\n");
|
||||
}
|
||||
fclose($file);
|
||||
return !$existed;
|
||||
}
|
||||
|
||||
function find_local(string $anyId): string | null {
|
||||
$found = [];
|
||||
foreach (scandir('.ids/') as $file) {
|
||||
if (!str_ends_with($file, '.txt')) continue;
|
||||
$data = file_get_contents(".ids/$file");
|
||||
if (str_contains($data, "\n$anyId\n"))
|
||||
$found[] = substr($file, 0, strlen($file) - 4);
|
||||
}
|
||||
return sizeof($found) === 1 ? $found[0] : null;
|
||||
}
|
||||
|
||||
function update_cache(string $country, string $postalCode): void {
|
||||
$anyNew = false;
|
||||
$traces = jget("https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/for/query?countryCode=$country&operatorPostalCode=$postalCode&sort=issuedOn");
|
||||
foreach ($traces as $op) {
|
||||
// traces
|
||||
$ooId = $op['operatorIdentifier'];
|
||||
$name = $op['operator']['name'];
|
||||
$address = $op['operator']['address']['street']['value'];
|
||||
$cityPostalCode = $op['operator']['address']['cityReference']['postalCode'];
|
||||
$cityName = $op['operator']['address']['cityReference']['name'];
|
||||
$new = update_local($ooId, ['plz' => $postalCode, 'name' => "$name|$address|$cityPostalCode $cityName"]);
|
||||
$anyNew = $anyNew || $new;
|
||||
}
|
||||
if (!$anyNew) return;
|
||||
|
||||
$m = curl_multi_init();
|
||||
$requests = [];
|
||||
foreach (['easy-cert', 'bioc', 'bioqs', 'lkv'] as $api) {
|
||||
$s = curl_init("https://elwig.at/organic/external/$api/operators?country=$country&postalCode=$postalCode");
|
||||
$requests[] = $s;
|
||||
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_multi_add_handle($m, $s);
|
||||
}
|
||||
|
||||
$running = 1;
|
||||
do {
|
||||
curl_multi_exec($m, $running);
|
||||
if ($running) usleep(250_000);
|
||||
} while ($running);
|
||||
foreach ($requests as $r) {
|
||||
curl_multi_remove_handle($m, $r);
|
||||
}
|
||||
curl_multi_close($m);
|
||||
$data = [];
|
||||
foreach ($requests as $s) {
|
||||
if (($json = curl_multi_getcontent($s)) === null) {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 34');
|
||||
echo "{\"error\":\"internal server error\"}\n";
|
||||
exit;
|
||||
}
|
||||
$data[] = json_decode($json, true)['data'];
|
||||
}
|
||||
|
||||
foreach ($data[0] as $op) {
|
||||
// easy-cert
|
||||
$ooId = find_local("easy-cert:$op[db]:$op[id]");
|
||||
$lfbisNr = null;
|
||||
if ($ooId === null && ($opDetails = jget($op['url'])) !== null) {
|
||||
foreach ($opDetails['certificates'] as $cert) {
|
||||
if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $cert['nr'], $matches) === 1) {
|
||||
$ooId = $matches[1];
|
||||
}
|
||||
}
|
||||
if ($ooId === null || $lfbisNr === null) {
|
||||
foreach ($opDetails['certificates'] as $cert) {
|
||||
if ($cert['pdfUrl'] === null) continue;
|
||||
$pdfDetails = pdf_fetch($cert['pdfUrl']);
|
||||
if (isset($pdfDetails['operator']['lfbisNr'])) $lfbisNr = $pdfDetails['operator']['lfbisNr'];
|
||||
if (!isset($pdfDetails['id'])) continue;
|
||||
if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $pdfDetails['id'], $matches) === 1) {
|
||||
$ooId = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($ooId === null)
|
||||
continue;
|
||||
update_local($ooId, ['plz' => $postalCode, 'lfbis' => $lfbisNr, 'easy-cert' => "$op[db]:$op[id]"]);
|
||||
}
|
||||
foreach ($data[1] as $op) {
|
||||
// bioc
|
||||
$ooId = find_local("bioc:$op[id]");
|
||||
if ($ooId === null && ($opDetails = jget($op['url'])) !== null) {
|
||||
foreach ($opDetails['certificates'] as $cert) {
|
||||
if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $cert['nr'], $matches) === 1) {
|
||||
$ooId = $matches[1];
|
||||
}
|
||||
}
|
||||
if ($ooId === null) {
|
||||
foreach ($opDetails['certificates'] as $cert) {
|
||||
if ($cert['pdfUrl'] === null) continue;
|
||||
$pdfDetails = pdf_fetch($cert['pdfUrl']);
|
||||
if (isset($pdfDetails['operator']['lfbisNr'])) $op['lfbisNr'] = $pdfDetails['operator']['lfbisNr'];
|
||||
if (!isset($pdfDetails['id'])) continue;
|
||||
if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $pdfDetails['id'], $matches) === 1) {
|
||||
$ooId = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($ooId === null)
|
||||
continue;
|
||||
update_local($ooId, ['plz' => $postalCode, 'bioc' => "$op[id]"]);
|
||||
}
|
||||
foreach ($data[2] as $op) {
|
||||
// bioqs
|
||||
$ooId = find_local("bioqs:$op[id]");
|
||||
$lfbisNr = null;
|
||||
if ($ooId === null || $lfbisNr === null) {
|
||||
foreach ($op['certificates'] as $cert) {
|
||||
if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $cert['nr'], $matches) === 1) {
|
||||
$ooId = $matches[1];
|
||||
}
|
||||
}
|
||||
if ($ooId === null || $lfbisNr === null) {
|
||||
foreach ($op['certificates'] as $cert) {
|
||||
if ($cert['pdfUrl'] === null) continue;
|
||||
$pdfDetails = pdf_fetch($cert['pdfUrl']);
|
||||
if (isset($pdfDetails['operator']['lfbisNr'])) $lfbisNr = $pdfDetails['operator']['lfbisNr'];
|
||||
if (!isset($pdfDetails['id'])) continue;
|
||||
if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $pdfDetails['id'], $matches) === 1) {
|
||||
$ooId = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($ooId === null)
|
||||
continue;
|
||||
update_local($ooId, ['plz' => $postalCode, 'lfbis' => $lfbisNr, 'bioqs' => "$op[id]"]);
|
||||
}
|
||||
foreach ($data[3] as $op) {
|
||||
// lkv
|
||||
$ooId = find_local("lkv:$op[id]");
|
||||
if ($ooId === null)
|
||||
continue;
|
||||
update_local($ooId, ['plz' => $postalCode, 'lfbis' => $op['lfbisNr'], 'lkv' => "$op[id]"]);
|
||||
update_local($ooId, ['plz' => $postalCode, 'lfbis' => $op['lfbisNr'], 'lkv' => "$op[id]"]);
|
||||
}
|
||||
}
|
||||
|
||||
$info = substr($_SERVER['PATH_INFO'], 1);
|
||||
if ($info === '') {
|
||||
// search
|
||||
$limit = $_GET['limit'] ?? null;
|
||||
$offset = intval($_GET['offset'] ?? "0");
|
||||
if ($limit === '') $limit = null;
|
||||
if ($limit !== null) $limit = intval($limit);
|
||||
|
||||
$country = $_GET['country'] ?? null;
|
||||
$postalCode = $_GET['postalCode'] ?? null;
|
||||
if ($country === null || $postalCode === null) {
|
||||
header('Status: 400');
|
||||
header('Content-Length: 109');
|
||||
echo "{\"error\":\"bad request\",\"message\":\"The 'country' and 'postalCode' request URL query parameters are required\"}\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
update_cache($country, $postalCode);
|
||||
|
||||
echo "{\"data\":[";
|
||||
if ($country === 'AT') {
|
||||
$first = true;
|
||||
foreach (scandir('.ids/') as $file) {
|
||||
if (!str_ends_with($file, '.txt') || !str_starts_with($file, '040-')) continue;
|
||||
$id = substr($file, 0, strlen($file) - 4);
|
||||
$data = file_get_contents(".ids/$file");
|
||||
if (str_starts_with($data, "plz:$postalCode\n")) {
|
||||
preg_match("/^name:(.*?)\|(.*?)\|([0-9]{4}) (.*?)$/m", $data, $name);
|
||||
preg_match("/^lfbis:(.*?)$/m", $data, $lfbis);
|
||||
if (!$first) echo ",";
|
||||
echo "\n ";
|
||||
echo jenc([
|
||||
'id' => $id,
|
||||
'lfbisNr' => $lfbis[1],
|
||||
'name' => $name[1],
|
||||
'address' => $name[2],
|
||||
'postalCode' => $name[3],
|
||||
'city' => $name[4],
|
||||
'country' => $country,
|
||||
'url' => "https://elwig.at/organic/operators/$id",
|
||||
]);
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "\n]}\n";
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
if (preg_match("/^((easy-cert:[a-z]+|bioqs|bioc|lkv):[0-9a-zA-Z-_]+|lfbis:[0-9]+)$/", $info) === 1) {
|
||||
$found = find_local($info);
|
||||
if ($found !== null) {
|
||||
header('Status: 303');
|
||||
header('Location: /organic/operators/' . $found);
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
header('Status: 404');
|
||||
header('Content-Length: 22');
|
||||
echo "{\"error\":\"not found\"}\n";
|
||||
exit;
|
||||
} else if (!file_exists(".ids/$info.txt")) {
|
||||
header('Status: 404');
|
||||
header('Content-Length: 22');
|
||||
echo "{\"error\":\"not found\"}\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = file_get_contents(".ids/$info.txt");
|
||||
preg_match("/^name:(.*?)\|(.*?)\|([0-9]{4}) (.*?)$/m", $data, $name);
|
||||
preg_match("/^lfbis:(.*?)$/m", $data, $lfbis);
|
||||
preg_match("/^easy-cert:(.*?)$/m", $data, $easyCert);
|
||||
preg_match("/^bioqs:(.*?)$/m", $data, $bioQs);
|
||||
preg_match("/^bioc:(.*?)$/m", $data, $bioC);
|
||||
|
||||
if (sizeof($easyCert) > 1 && ($opDetails = jget("https://elwig.at/organic/external/easy-cert/operators/$easyCert[1]")) !== null) {
|
||||
foreach ($opDetails['certificates'] as $cert) {
|
||||
if ($cert['pdfUrl'] === null) continue;
|
||||
pdf_fetch($cert['pdfUrl']);
|
||||
}
|
||||
}
|
||||
if (sizeof($bioQs) > 1 && ($opDetails = jget("https://elwig.at/organic/external/bioqs/operators/$bioQs[1]")) !== null) {
|
||||
foreach ($opDetails['certificates'] as $cert) {
|
||||
if ($cert['pdfUrl'] === null) continue;
|
||||
pdf_fetch($cert['pdfUrl']);
|
||||
}
|
||||
}
|
||||
if (sizeof($bioC) > 1 && ($opDetails = jget("https://elwig.at/organic/external/bioc/operators/$bioC[1]")) !== null) {
|
||||
foreach ($opDetails['certificates'] as $cert) {
|
||||
if ($cert['pdfUrl'] === null) continue;
|
||||
pdf_fetch($cert['pdfUrl']);
|
||||
}
|
||||
}
|
||||
|
||||
$certs = [];
|
||||
$certIds = [];
|
||||
foreach (scandir('../certificates/') as $file) {
|
||||
if (!str_contains($file, ".$info."))
|
||||
continue;
|
||||
$certId = substr($file, 0, 31);
|
||||
if (in_array($certId, $certIds))
|
||||
continue;
|
||||
$certIds[] = $certId;
|
||||
$cert = parse_pdf("../certificates/$certId.pdf");
|
||||
$appendix = parse_pdf("../certificates/$certId.appendix.pdf");
|
||||
if ($cert === null && $appendix === null)
|
||||
continue;
|
||||
|
||||
$parts = explode('.', $file);
|
||||
$certs[] = [
|
||||
'id' => $certId,
|
||||
'nr' => $appendix['nr'] ?? null,
|
||||
'validFrom' => $cert['validFrom'] ?? null,
|
||||
'validTo' => $cert['validTo'] ?? null,
|
||||
'authority' => ['code' => $parts[0]],
|
||||
'operator' => ['id' => $parts[1]],
|
||||
'url' => "https://elwig.at/organic/certificates/$certId",
|
||||
'tracesPdfUrl' => $cert !== null ? "https://elwig.at/organic/certificates/$certId.pdf" : null,
|
||||
'appendixPdfUrl' => $appendix !== null ? "https://elwig.at/organic/certificates/$certId.appendix.pdf" : null,
|
||||
];
|
||||
}
|
||||
|
||||
$details = [];
|
||||
if (preg_match("/^easy-cert:(.*?)$/m", $data, $easyCert) === 1)
|
||||
$details[] = "https://elwig.at/organic/external/easy-cert/operators/$easyCert[1]";
|
||||
if (preg_match("/^bioc:(.*?)$/m", $data, $bioc) === 1)
|
||||
$details[] = "https://elwig.at/organic/external/bioc/operators/$bioc[1]";
|
||||
if (preg_match("/^bioqs:(.*?)$/m", $data, $bioqs) === 1)
|
||||
$details[] = "https://elwig.at/organic/external/bioqs/operators/$bioqs[1]";
|
||||
if (preg_match("/^lkv:(.*?)$/m", $data, $lkv) === 1)
|
||||
$details[] = "https://elwig.at/organic/external/lkv/operators/$lkv[1]";
|
||||
echo jenc([
|
||||
'id' => $info,
|
||||
'lfbisNr' => $lfbis[1],
|
||||
'name' => $name[1],
|
||||
'address' => $name[2],
|
||||
'postalCode' => $name[3],
|
||||
'city' => $name[4],
|
||||
'country' => 'AT',
|
||||
'url' => "https://elwig.at/organic/operators/$info",
|
||||
'tracesUrl' => "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/index#!?query=$info",
|
||||
'originUrls' => $details,
|
||||
'certificates' => $certs,
|
||||
]);
|
||||
Reference in New Issue
Block a user