organic: Enhance external apis

This commit is contained in:
2025-12-22 16:56:23 +01:00
parent 551ddd3c11
commit 0cd3b3de8e
10 changed files with 350 additions and 110 deletions

View File

@@ -1,11 +1,15 @@
<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json; charset=UTF-8');
$base = 'https://' . $_SERVER['SERVER_NAME'] . explode('?', $_SERVER['REQUEST_URI'])[0];
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
header('Status: 405');
header('Content-Length: 0');
header('Content-Length: 56');
header('Allow: GET, HEAD');
echo "{\"error\":\"method not allowed\",\"allow\":[\"GET\",\"HEAD\"]}\n";
exit;
}
@@ -16,17 +20,84 @@ function jenc($data): string {
$info = $_SERVER['PATH_INFO'];
if ($info !== '') {
$id = substr($info, 1);
$url = "https://www.bioc.info/search/producerdetail?producer=" . urlencode($id);
$s = curl_init($url);
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
if (($html = curl_exec($s)) === false) {
header('Status: 500');
header('Content-Length: 34');
echo "{\"error\":\"internal server error\"}\n";
exit;
}
$p1 = strpos($html, '<main>');
$p2 = strpos($html, '</main>');
if ($p1 === false || $p2 === false) {
header('Status: 404');
header('Content-Length: 0');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
exit;
}
$html = substr($html, $p1 + 6, $p2 - $p1 - 6);
$data = [];
preg_match_all('@<div class="row">\s*<div class="col[^>]*?>\s*(.*?)\s*</div>\s*<div class="col[^>]*?>\s*(.*?)\s*</div>\s*</div>@s', $html, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$data[$m[1]] = trim(preg_replace('/\s*\n\s*/', "\n", html_entity_decode(preg_replace('/<.*?>/', '', str_replace('<br/>', "\n", preg_replace('/\s+/', ' ', trim($m[2])))))));
}
$certRows = [];
preg_match_all('@<tr>\s*<td.*?href="([^"]*)">\s*(.*?)\s*</td>\s*<td>\s*(.*?)\s*</td>\s*<td>\s*(.*?)\s*</td>\s*<td>\s*(.*?)\s*</td>\s*</tr>@s', $html, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$cert = [];
foreach (array_splice($m, 1) as $s) {
$cert[] = trim(preg_replace('/\s*\n\s*/', "\n", preg_replace('/<.*?>/', '', str_replace('<br/>', "\n", preg_replace('/\s+/', ' ', trim(html_entity_decode($s)))))));
}
$certRows[] = $cert;
}
$lines = explode("\n", $data['Address']);
[$cc, $_, $postalCode, $city] = explode(' ', $lines[2], 4);
$certs = [];
foreach ($certRows as $row) {
[$nr, $lang] = explode('(', $row[1], 2);
[$from, $to] = explode(' - ', $row[3], 2);
$certs[] = [
'nr' => trim($nr),
'language' => substr($lang, 0, 2),
'pdfUrl' => $row[0],
'type' => $row[2],
'validFrom' => date('Y-m-d', strtotime($from)),
'validUntil' => date('Y-m-d', strtotime($to)),
];
}
[$authCode, $authName] = explode(' ', $data['Certification body'], 2);
echo jenc([
'id' => $id,
'idNr' => $data['Operator ID'] ?? null,
'name' => $lines[0],
'address' => $lines[1],
'postalCode' => $postalCode,
'city' => $city,
'countryCode' => $cc,
'authority' => ['code' => $authCode, 'name' => $authName],
'url' => $base,
'originUrl' => $url,
'certificates' => $certs,
]);
exit;
}
$source_groups = [
['', '0892fdd7-6649-cb3b-75ef-a60649cfebfd'],
['', 'fde4ccef-0f36-4db9-9f2f-9bb6009c872a'],
['', '8e6d20d3-6bbe-c7ae-7a77-fb7fa80ee291'],
['', '830b3bd7-f1da-e20e-300d-e561bfb8205b'],
['', 'ed025d59-056f-ffd0-79e0-05348fe88d59'],
['', '95d536c8-c869-9f72-1bce-4256a2a4ce49'],
['',
'0892fdd7-6649-cb3b-75ef-a60649cfebfd', 'fde4ccef-0f36-4db9-9f2f-9bb6009c872a',
'8e6d20d3-6bbe-c7ae-7a77-fb7fa80ee291', '830b3bd7-f1da-e20e-300d-e561bfb8205b',
'ed025d59-056f-ffd0-79e0-05348fe88d59', '95d536c8-c869-9f72-1bce-4256a2a4ce49'
], [ '',
'bef6b49a-3186-ba7f-fffb-281bfb4ca2d2', 'fc7a0cc3-c4b4-a4fb-5b7e-5cf9b68ed198',
'9aecd829-8f3c-6829-449f-9cb511e0c1ff', 'e7a7089b-0fd7-60b9-48af-c0988a90ec37',
'63d570d8-0ab2-b793-fe11-62e0777e4236'
@@ -43,38 +114,44 @@ $idNr = $_GET['idNr'] ?? null;
if ($country === null) {
header('Status: 400');
header('Content-Length: 0');
header('Content-Length: 88');
echo "{\"error\":\"bad request\",\"message\":\"The 'country' request URL query parameter is required\"}\n";
exit;
}
$data = [];
$url = "https://www.bioc.info/search/producerSearchQuery?search[name]=" . urlencode($name) . "&search[citycode]=" . urlencode($postalCode) . "&search[operatorId]=" . urlencode($idNr) . "&search[country]=$country";
if ($_GET['allDBs'] === 'true') {
$s = curl_init($url . implode('&sources[]=', $source_groups[0]));
$m = curl_multi_init();
$requests = [];
foreach ($source_groups as $group) {
$s = curl_init($url . implode('&sources[]=', $group));
$requests[] = $s;
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
if (($json = curl_exec($s)) === false) {
header('Status: 500');
header('Content-Length: 0');
exit;
}
$res = json_decode($json, true)['results'];
foreach ($res as $r) {
$data[$r['id']] = $r['row'];
}
curl_multi_add_handle($m, $s);
}
$s = curl_init($url . implode('&sources[]=', $source_groups[1]));
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
if (($json = curl_exec($s)) === false) {
$running = 1;
do {
curl_multi_exec($m, $running);
} while ($running);
foreach ($requests as $r) {
curl_multi_remove_handle($m, $r);
}
curl_multi_close($m);
foreach ($requests as $s) {
if (($json = curl_multi_getcontent($s)) === false) {
header('Status: 500');
header('Content-Length: 0');
header('Content-Length: 34');
echo "{\"error\":\"internal server error\"}\n";
exit;
}
$res = json_decode($json, true)['results'];
foreach ($res as $r) {
$data[$r['id']] = $r['row'];
}
}
header('Content-Type: application/json; charset=UTF-8');
@@ -90,8 +167,8 @@ foreach ($data as $id => $row) {
'name' => substr($row[0], strrpos($row[0], '>') + 1),
'postalCode' => substr($row[1], strrpos($row[1], '>') + 1),
'city' => substr($row[2], strrpos($row[2], '>') + 1),
'authorityCode' => $auth[0],
'authorityName' => $auth[1],
'authority' => ['code' => $auth[0], 'name' => $auth[1]],
'url' => "$base/$id",
]);
$first = false;
}

View File

@@ -18,10 +18,16 @@ def main() -> None:
args = parser.parse_args()
s = requests.Session()
while True:
try:
r = s.get(f'{URL}?menu_sid=5002')
uri = ACTION_RE.findall(r.text)[0]
break
except IndexError:
pass
hidden = {m[1]: m[2] for m in HIDDEN_RE.finditer(r.text)}
while True:
r = s.post(f'{BASE_URL}{uri}', data={
'PartnerCertSearchForm:pcs_seqidall': args.cert_nr,
'PartnerCertSearchForm:button_search': 'Suche starten...',
@@ -29,12 +35,17 @@ def main() -> None:
'javax.faces.ViewState': hidden['javax.faces.ViewState'],
})
if 'class="msg_error"' in r.text:
print(f'404', file=sys.stderr)
exit(1)
p1 = r.text.find(f'>{args.cert_nr}<')
p2 = r.text.find('id="', p1)
p3 = r.text.find('"', p2 + 4)
if p1 == -1 or p2 == -1 or p3 == -1:
exit(1)
continue
id = r.text[p2 + 4:p3]
break
r = s.post(f'{BASE_URL}{uri}', data={
'PartnerCertSearchForm:_idcl': id,

View File

@@ -33,8 +33,13 @@ def main() -> None:
query = {'PartnerCertSearchForm:pcs_' + q.split('=', 1)[0]: urllib.parse.unquote(q.split('=', 1)[-1]) for q in args.query.split('&')}
s = requests.Session()
while True:
try:
r = s.get(f'{URL}?menu_sid=5002')
uri = ACTION_RE.findall(r.text)[0]
break
except IndexError:
pass
hidden = {m[1]: m[2] for m in HIDDEN_RE.finditer(r.text)}
r = s.post(f'{BASE_URL}{uri}', data={
@@ -69,7 +74,7 @@ def main() -> None:
'validTo': '-'.join(reversed(srow[2].split('-'))),
'type': srow[3],
'attachmentSid': srow[4],
'url': f'https://elwig.at/organic/external/bioqs/attachments/{urllib.parse.quote(srow[0])}',
'pdfUrl': f'https://elwig.at/organic/external/bioqs/attachments/{urllib.parse.quote(srow[0])}',
})
if not first:
print(',', flush=True)
@@ -80,10 +85,10 @@ def main() -> None:
'postalCode': row[3],
'city': row[4],
'address': row[5],
'autorityName': meta['Kontrollstelle'],
'authority': {'name': meta['Kontrollstelle']},
'productGroups': meta['Bereiche'],
'certificates': certificates,
}, ensure_ascii=False), end='')
}, ensure_ascii=False, separators=(',',':')), end='')
first = False
print('\n]')

View File

@@ -3,30 +3,38 @@
header('Access-Control-Allow-Origin: *');
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
header('Content-Type: application/json; charset=UTF-8');
header('Status: 405');
header('Content-Length: 0');
header('Content-Length: 56');
header('Allow: GET, HEAD');
echo "{\"error\":\"method not allowed\",\"allow\":[\"GET\",\"HEAD\"]}\n";
exit;
}
$info = $_SERVER['PATH_INFO'];
if ($info === '') {
header('Content-Type: application/json; charset=UTF-8');
header('Status: 404');
header('Content-Length: 0');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
exit;
}
$certId = substr($info, 1);
$file = tmpfile();
if (!$file) {
header('Content-Type: application/json; charset=UTF-8');
header('Status: 500');
header('Content-Length: 0');
header('Content-Length: 34');
echo "{\"error\":\"internal server error\"}\n";
exit;
}
$filename = stream_get_meta_data($file)['uri'];
if (($pdfName = exec("python3 .attachment.py " . escapeshellarg($certId) . " 2>&1 > $filename ")) === false) {
header('Status: 500');
header('Content-Length: 0');
if (($pdfName = exec("python3 .attachment.py " . escapeshellarg($certId) . " 2>&1 > $filename ")) === "404") {
header('Content-Type: application/json; charset=UTF-8');
header('Status: 404');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
exit;
}

View File

@@ -1,18 +1,21 @@
<?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: 0');
header('Content-Length: 56');
header('Allow: GET, HEAD');
echo "{\"error\":\"method not allowed\",\"allow\":[\"GET\",\"HEAD\"]}\n";
exit;
}
$info = $_SERVER['PATH_INFO'];
if ($info !== '') {
header('Status: 404');
header('Content-Length: 0');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
exit;
}
@@ -36,8 +39,6 @@ if (isset($_GET['lfbisNr'])) {
$query[] = 'lfbis=' . urlencode($_GET['lfbisNr']);
}
header('Content-Type: application/json; charset=UTF-8');
echo "{\"data\":";
passthru("python3 .operators.py " . escapeshellarg(implode('&', $query)));
echo "}\n";

View File

@@ -1,11 +1,15 @@
<?php
header('Access-Control-Allow-Origin: *');
header("Content-Type: application/json; charset=UTF-8");
$base = 'https://' . $_SERVER['SERVER_NAME'] . explode('?', $_SERVER['REQUEST_URI'])[0];
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
header('Status: 405');
header('Content-Length: 0');
header('Content-Length: 56');
header('Allow: GET, HEAD');
echo "{\"error\":\"method not allowed\",\"allow\":[\"GET\",\"HEAD\"]}\n";
exit;
}
@@ -22,13 +26,15 @@ if ($info !== '') {
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
if (($json = curl_exec($s)) === false) {
header('Status: 500');
header('Content-Length: 0');
header('Content-Length: 34');
echo "{\"error\":\"internal server error\"}\n";
exit;
}
$json = json_decode($json);
if ($json->{'totalCount'} !== 1) {
header('Status: 404');
header('Content-Length: 0');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
exit;
}
header('Status: 303');
@@ -36,7 +42,6 @@ if ($info !== '') {
exit;
}
$refDate = $_GET['referenceDate'] ?? null;
if ($refDate !== null) {
$refDate = explode('-', $refDate);
@@ -47,7 +52,8 @@ if ($info !== '') {
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
if (($html = curl_exec($s)) === false) {
header('Status: 500');
header('Content-Length: 0');
header('Content-Length: 34');
echo "{\"error\":\"internal server error\"}\n";
exit;
}
@@ -73,7 +79,8 @@ if ($info !== '') {
if ($data['Name'] === null) {
header('Status: 404');
header('Content-Length: 0');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
exit;
}
@@ -107,21 +114,21 @@ if ($info !== '') {
];
}
header("Content-Type: application/json; charset=UTF-8");
echo '{"db":' . jenc($parts[0]) .
',"id":' . jenc($parts[1]) .
",\n \"idNr\":" . jenc($data['ID-Nummer'] ?? null) .
',"name":' . jenc($data['Name']) .
',"address":' . jenc($data['Strasse'] ?? null) .
',"postalCode":' . jenc($postalCode) .
',"city":' . jenc($city) .
',"countryCode":' . jenc($data['Land'] ?? null) .
",\n \"referenceDate\":" . jenc($refDate) .
",\n \"certificates\":" . jenc($certs) .
",\n \"privateStandardApprovals\":" . jenc($labels) .
'}';
echo jenc([
'db' => $parts[0],
'id' => $parts[1],
'idNr' => $data['ID-Nummer'] ?? null,
'name' => $data['Name'],
'address' => $data['Strasse'] ?? null,
'postalCode' => $postalCode,
'city' => $city,
'countryCode' => $data['Land'] ?? null,
'url' => $base,
'originUrl' => $url,
'referenceDate' => $refDate,
'certificates' => $certs,
'privateStandardApprovals' => $labels,
]);
exit;
}
@@ -207,12 +214,12 @@ if ($url === null) {
}
if ($url === null) {
header("Status: 500");
header("Content-Length: 0");
header('Status: 500');
header('Content-Length: 34');
echo "{\"error\":\"internal server error\"}\n";
exit;
}
$sed = [
's/^.*"searchresults":\[//',
's/],.*$//',
@@ -235,8 +242,6 @@ $replace = [
];
$replaceSed = array_map(fn($v, $k): string => "s/$k/$v/", $replace, array_keys($replace));
header("Content-Type: application/json; charset=UTF-8");
echo '{"searchUrl":' . jenc($search_url) .
',"queryId":' . jenc($query_id) .
',"rawFileUrl":' . jenc($url) .
@@ -262,6 +267,7 @@ $process = proc_open(
"tail -n +$offset | " . // apply offset
($limit !== null ? " head -n $limit | " : "") . // optionally apply limit
"sed '" . implode(';', $replaceSed) . "' | " . // replace strings in json
"sed 's|{\\(\"db\":\"\\([^\"]*\\)\".*\"id\":\"\\([^\"]*\\)\".*\\)}|{\\1,\"url\":\"$base/\\2:\\3\"}|' | " . // add "url"
"sed '\$s/.$//'"], // remove last comma of last line
$fd_spec,
$pipes

45
www/organic/external/index.php vendored Normal file
View File

@@ -0,0 +1,45 @@
<?php
$APIS = [
'bioc' => ['id' => 'bioc', 'endpoints' => ['https://elwig.at/organic/external/bioc/operators']],
'bioqs' => ['id' => 'bioqs', 'endpoints' => ['https://elwig.at/organic/external/bioqs/operators', 'https://elwig.at/organic/external/bioqs/attachments']],
'easy-cert' => ['id' => 'easy-cert', 'endpoints' => ['https://elwig.at/organic/external/easy-cert/operators']],
'lkv' => ['id' => 'lkv', 'endpoints' => ['https://elwig.at/organic/external/lkv/operators']],
];
function jenc($data): string {
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
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;
}
if ($_SERVER['PATH_INFO'] !== '') {
$code = rtrim(substr($_SERVER['PATH_INFO'], 1), '/');
header('Content-Type: application/json; charset=UTF-8');
if (array_key_exists($code, $APIS)) {
echo jenc($APIS[$code]);
echo "\n";
exit;
}
header('Status: 404');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
}
echo "{\"apis\":[\n";
$first = true;
foreach ($APIS as $api) {
if (!$first) echo ",\n";
echo " " . jenc($api);
$first = false;
}
echo "\n]}\n";

View File

@@ -1,11 +1,15 @@
<?php
$url = 'https://lkv.at/at/zertifizierung/themen/BIO/zertifizierte-BIO-Betriebe.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: 0');
header('Content-Length: 56');
header('Allow: GET, HEAD');
echo "{\"error\":\"method not allowed\",\"allow\":[\"GET\",\"HEAD\"]}\n";
exit;
}
@@ -16,18 +20,39 @@ function jenc($data): string {
$info = $_SERVER['PATH_INFO'];
if ($info !== '') {
header('Status: 404');
header('Content-Length: 0');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
exit;
}
header('Content-Type: application/json; charset=UTF-8');
echo "{\"data\":[\n";
$postalCode = '';
if (isset($_GET['postalCode']) && ctype_digit($_GET['postalCode'])) {
$postalCode = $_GET['postalCode'];
}
$lfbisNr = '';
if (isset($_GET['lfbisNr'])) {
if (strlen($_GET['lfbisNr']) === 7) {
$lfbisNr = '"' . $_GET['lfbisNr'];
} else {
$lfbisNr = 'invalid';
}
}
echo "{\"sourceUrl\":\"$url\",\"data\":[\n";
passthru(<<<EOF
curl -s 'https://lkv.at/at/zertifizierung/themen/BIO/zertifizierte-BIO-Betriebe.php' | grep '<tr' -A 3 \
| sed 's@<tr>@ {@;s@</tr>@ },@;s@<td><a .*href="\([^"]*\)".*>\(.*\)</a></td>@ "certUrl":"\\1","certNr":"\\2",@;s@<td>\(.*\)<br/>\(.*\)<br/>\([0-9]*\) \(.*\)</td>@ "name":"\\1","address":"\\2","postalCode":"\\3","city":"\\4"@;s@<td>\(.*\)<br/>\(.*\)</td>@ "name":"\\1","type":"\\2"@;\$s/.$//' \
| sed 's@"certUrl":"\(/[^"]*\)"@"certUrl":"https://lkv.at\\1"@' \
curl -s '$url' | grep -A3 '<tr' \
| sed 's@<tr>@ {@;s@</tr>@ },@;s@<td><a .*href="\([^"]*\)".*>\(.*\)</a></td>@ "certUrl":"\\1","certNr":"\\2",@;s@<td>\(.*\)<br/>\(.*\)<br/>\([0-9]*\) \([^<]*\)\(<br/>\)\?</td>@ "name":"\\1","address":"\\2","postalCode":"\\3","city":"\\4"@;s@<td>\(.*\)<br/>\(.*\)</td>@ "name":"\\1","type":"\\2"@' \
| sed 's@"certUrl":"\(/[^"]*\)"@"certUrl":"https://lkv.at\\1"@;s@"certNr":"[^0-9]*0\?\([0-9]\{7\}\|[0-9]\{1,4\}\|[0-9]\{7,\}\)_[^"]*"@\\0,"id":"\\1"@;s@"id":"\([0-9]\{7\}\)"@\\0,"lfbisNr":"\\1"@;s@"id":"\([^"]\{,6\}\|[^"]\{8,\}\)"@\\0,"lfbisNr":null@' \
| sed 's@"certUrl":"\([^"]*\)","certNr":"\([^"]*\)",@"certificates":[{"pdfUrl":"\\1","nr":"\\2"}],\\n @' \
| perl -ne 'BEGIN { our \$N = 8; our @buf; } push @buf, \$_; if (@buf > \$N) { print shift @buf; } my \$chunk = join "", @buf;
if (\$chunk =~ /(}],\n(?:.*\n){6}\s*"name":"[^"]*","type":)/) {
\$chunk =~ s/(}],\n((?:.*\n){2})(?:.*\n){2}\s*"certificates":\[\{"pdfUrl":"([^"]*)","nr":"([^"]*)"\}\],\n.*\n\s*"name":"[^"]*","type":"([^"]*)")/},{"pdfUrl":"\$3","nr":"\$4","type":"\$5"}],\n\$2/;
@buf = map { "\$_\n" } split /\n/, \$chunk;
} END { print for @buf; }' \
| grep -B3 -A1 --no-group-separator '"postalCode":"$postalCode' | grep -B2 -A2 --no-group-separator '"lfbisNr":$lfbisNr' \
| sed '\$s/.$//'
| sed 's@\s*",@",@g;s@:"\s*@:"@g'
EOF);
echo "]}\n";

View File

@@ -1,16 +1,58 @@
<?php
$AUTHORITIES = [
'AT-BIO-301' => [
'id' => 'AT-BIO-301', 'countryCode' => 'AT', 'handle' => 'ABG',
'name' => 'Austria Bio Garantie GmbH', 'website' => 'https://www.bio-garantie.at/', 'apis' => ['easy-cert']
],
'AT-BIO-302' => [
'id' => 'AT-BIO-302', 'countryCode' => 'AT', 'handle' => 'ABG-LW',
'name' => 'Austria Bio Garantie Landwirtschaft GmbH', 'website' => 'https://www.bio-garantie.at/', 'apis' => ['easy-cert']
],
'AT-BIO-401' => [
'id' => 'AT-BIO-401', 'countryCode' => 'AT', 'handle' => 'BIOS',
'name' => 'BIOS Biokontrollservice Österreich GmbH', 'website' => 'https://www.bios-kontrolle.at/', 'apis' => ['bioqs']
],
'AT-BIO-402' => [
'id' => 'AT-BIO-402', 'countryCode' => 'AT', 'handle' => 'LACON',
'name' => 'LACON GmbH ', 'website' => 'https://www.lacon-institut.com/', 'apis' => ['easy-cert']
],
'AT-BIO-501' => [
'id' => 'AT-BIO-501', 'countryCode' => 'AT', 'handle' => 'SLK',
'name' => 'SLK GesmbH', 'website' => 'https://slk.at/', 'apis' => ['bioc']
],
'AT-BIO-901' => [
'id' => 'AT-BIO-901', 'countryCode' => 'AT', 'handle' => 'LVA',
'name' => 'LVA GmbH', 'website' => 'https://www.lva.at/', 'apis' => []
],
'AT-BIO-902' => [
'id' => 'AT-BIO-902', 'countryCode' => 'AT', 'handle' => 'SGS',
'name' => 'SGS Austria Controll-Co. Ges.m.b.H.', 'website' => 'https://www.sgs.com/de-at ', 'apis' => ['bioc']
],
'AT-BIO-903' => [
'id' => 'AT-BIO-903', 'countryCode' => 'AT', 'handle' => 'LKV',
'name' => 'LKV Austria Gemeinnützige GmbH', 'website' => 'https://www.lkv.at/', 'apis' => ['bioc', 'lkv']
],
];
header('Access-Control-Allow-Origin: *');
function jenc($data): string {
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
header('Content-Type: application/json; charset=UTF-8');
header('Status: 405');
header('Content-Length: 0');
header('Content-Length: 56');
header('Allow: GET, HEAD');
echo "{\"error\":\"method not allowed\",\"allow\":[\"GET\",\"HEAD\"]}\n";
exit;
}
$info = $_SERVER['PATH_INFO'];
if ($info !== '/' && str_ends_with($info, '/')) {
header('Status: 303');
header('Content-Length: 0');
header('Location: /organic/' . substr($info, 0, -1));
exit;
}
@@ -22,8 +64,10 @@ if (str_starts_with($info, '/certificates/')) {
$id = substr($id, 0, -4);
}
if (str_contains($id, '/') || !file_exists("certificates/$id.pdf")) {
header('Content-Length: 0');
header('Content-Type: application/json; charset=UTF-8');
header('Status: 404');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
exit;
}
if (str_ends_with($parts[2], '.txt')) {
@@ -52,28 +96,32 @@ if (str_starts_with($info, '/certificates/')) {
exit;
} else if ($info === '/authorities') {
header('Content-Type: application/json; charset=UTF-8');
echo <<<EOF
{"data":[
{"id":"AT-BIO-301","countryCode":"AT","handle":"ABG","name":"Austria Bio Garantie GmbH","website":"https://www.bio-garantie.at/","apis":["easy-cert"]},
{"id":"AT-BIO-302","countryCode":"AT","handle":"ABG-LW","name":"Austria Bio Garantie Landwirtschaft GmbH","website":"https://www.bio-garantie.at/","apis":["easy-cert"]},
{"id":"AT-BIO-401","countryCode":"AT","handle":"BIOS","name":"BIOS Biokontrollservice Österreich GmbH","website":"https://www.bios-kontrolle.at/","apis":["bioqs"]},
{"id":"AT-BIO-402","countryCode":"AT","handle":"LACON","name":"LACON GmbH ","website":"https://www.lacon-institut.com/","apis":["easy-cert"]},
{"id":"AT-BIO-501","countryCode":"AT","handle":"SLK","name":"SLK GesmbH","website":"https://slk.at/","apis":["bioc"]},
{"id":"AT-BIO-901","countryCode":"AT","handle":"LVA","name":"LVA GmbH","website":"https://www.lva.at/","apis":[]},
{"id":"AT-BIO-902","countryCode":"AT","handle":"SGS","name":"SGS Austria Controll-Co. Ges.m.b.H.","website":"https://www.sgs.com/de-at ","apis":["bioc"]},
{"id":"AT-BIO-903","countryCode":"AT","handle":"LKV","name":"LKV Austria Gemeinnützige GmbH","website":"https://www.lkv.at/","apis":["bioc","lkv"]}
]}
EOF;
echo "{\"data\":[\n";
$first = true;
foreach ($AUTHORITIES as $auth) {
if (!$first) echo ",\n";
echo " " . jenc($auth);
$first = false;
}
echo "\n]}\n";
exit;
} else if (str_starts_with($info, '/authorities/')) {
$code = $parts[2];
header('Content-Type: text/plain; charset=UTF-8');
echo "Control Authority Code: $code\n";
header('Content-Type: application/json; charset=UTF-8');
if (array_key_exists($code, $AUTHORITIES)) {
echo jenc($AUTHORITIES[$code]);
echo "\n";
} else {
header('Status: 404');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";
}
exit;
} else if ($info === '/operators') {
header('Content-Type: application/json; charset=UTF-8');
header('Status: 501');
header('Content-Length: 27');
echo "{\"error\":\"not implemented\"}\n";
exit;
} else if (str_starts_with($info, '/operators/')) {
$ooid = $parts[2];
@@ -82,5 +130,6 @@ EOF;
exit;
}
header('Content-Length: 0');
header('Status: 404');
header('Content-Length: 22');
echo "{\"error\":\"not found\"}\n";

View File

@@ -224,8 +224,21 @@ if ($format === 'text') {
$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\":{},\n \"authority\":{\"id\":" . jenc($authorityId) . "}}\n";
echo ",\n \"operator\":" . jenc($operator) . ",\n \"authority\":{\"id\":" . jenc($authorityId) . "}}\n";
exit;
}