Compare commits
7 Commits
8757940a3c
...
main
Author | SHA1 | Date | |
---|---|---|---|
cc3c0cab45 | |||
a44f886086 | |||
3a39cb6635 | |||
40093957a3 | |||
f108f026b9 | |||
fffc450e87 | |||
a3c401ead2 |
99
www/organic/external/bioc/operators.php
vendored
Normal file
99
www/organic/external/bioc/operators.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
||||
header('Status: 405');
|
||||
header('Content-Length: 0');
|
||||
header('Allow: GET, HEAD');
|
||||
exit;
|
||||
}
|
||||
|
||||
function jenc($data): string {
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
$info = $_SERVER['PATH_INFO'];
|
||||
if ($info !== '') {
|
||||
$id = substr($info, 1);
|
||||
header('Status: 404');
|
||||
header('Content-Length: 0');
|
||||
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'
|
||||
], [ '',
|
||||
'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'
|
||||
],
|
||||
];
|
||||
|
||||
$country = [
|
||||
'AT' => 'a1e51f85-27b5-a1e3-65f7-561569884d38',
|
||||
'DE' => '1be4d468-ba47-08f1-f048-f45869af856f',
|
||||
][$_GET['country'] ?? null] ?? null;
|
||||
$postalCode = $_GET['postalCode'] ?? null;
|
||||
$name = $_GET['name'] ?? null;
|
||||
$idNr = $_GET['idNr'] ?? null;
|
||||
|
||||
if ($country === null) {
|
||||
header('Status: 400');
|
||||
header('Content-Length: 0');
|
||||
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]));
|
||||
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'];
|
||||
}
|
||||
}
|
||||
|
||||
$s = curl_init($url . implode('&sources[]=', $source_groups[1]));
|
||||
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'];
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
|
||||
$first = true;
|
||||
echo "{\"data\":[\n";
|
||||
foreach ($data as $id => $row) {
|
||||
if (!$first) echo ",\n";
|
||||
$row = explode("</", $row);
|
||||
$auth = explode(' ', substr($row[3], strrpos($row[3], '>') + 1), 2);
|
||||
echo " ";
|
||||
echo jenc([
|
||||
'id' => $id,
|
||||
'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],
|
||||
]);
|
||||
$first = false;
|
||||
}
|
||||
echo "\n]}\n";
|
||||
|
54
www/organic/external/bioqs/.attachment.py
vendored
Executable file
54
www/organic/external/bioqs/.attachment.py
vendored
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/env python3
|
||||
|
||||
import re
|
||||
import argparse
|
||||
import requests
|
||||
import sys
|
||||
|
||||
|
||||
BASE_URL = 'https://www.bioqs.at'
|
||||
URL = f'{BASE_URL}/ACM/faces/form/cms/portal/index.jsp'
|
||||
ACTION_RE = re.compile(r'action="([^"]*)"')
|
||||
HIDDEN_RE = re.compile(r'<input type="hidden" name="([^"]*)" .*?value="([^"]*)"')
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('cert_nr', type=str)
|
||||
args = parser.parse_args()
|
||||
|
||||
s = requests.Session()
|
||||
r = s.get(f'{URL}?menu_sid=5002')
|
||||
uri = ACTION_RE.findall(r.text)[0]
|
||||
hidden = {m[1]: m[2] for m in HIDDEN_RE.finditer(r.text)}
|
||||
|
||||
r = s.post(f'{BASE_URL}{uri}', data={
|
||||
'PartnerCertSearchForm:pcs_seqidall': args.cert_nr,
|
||||
'PartnerCertSearchForm:button_search': 'Suche starten...',
|
||||
'PartnerCertSearchForm_SUBMIT': '1',
|
||||
'javax.faces.ViewState': hidden['javax.faces.ViewState'],
|
||||
})
|
||||
|
||||
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)
|
||||
id = r.text[p2 + 4:p3]
|
||||
|
||||
r = s.post(f'{BASE_URL}{uri}', data={
|
||||
'PartnerCertSearchForm:_idcl': id,
|
||||
'PartnerCertSearchForm_SUBMIT': '1',
|
||||
'javax.faces.ViewState': hidden['javax.faces.ViewState'],
|
||||
})
|
||||
|
||||
if 'Content-Disposition' in r.headers:
|
||||
dispo = r.headers['Content-Disposition']
|
||||
if 'filename="' in dispo:
|
||||
filename = dispo[dispo.find('filename="') + 10:dispo.rfind('"')]
|
||||
print(filename, file=sys.stderr)
|
||||
sys.stdout.buffer.write(r.content)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
92
www/organic/external/bioqs/.operators.py
vendored
Executable file
92
www/organic/external/bioqs/.operators.py
vendored
Executable file
@@ -0,0 +1,92 @@
|
||||
#!/bin/env python3
|
||||
|
||||
import re
|
||||
import argparse
|
||||
import requests
|
||||
import html
|
||||
import json
|
||||
import urllib.parse
|
||||
|
||||
|
||||
BASE_URL = 'https://www.bioqs.at'
|
||||
URL = f'{BASE_URL}/ACM/faces/form/cms/portal/index.jsp'
|
||||
ACTION_RE = re.compile(r'action="([^"]*)"')
|
||||
HIDDEN_RE = re.compile(r'<input type="hidden" name="([^"]*)" .*?value="([^"]*)"')
|
||||
|
||||
ROW_RE = re.compile(r'<tr[^>]*>\s*(.*?)\s*</tr>', re.DOTALL)
|
||||
UNCOLLAPSED_ROW_RE = re.compile(r'<tr style="">(\s*<td>\s*(.*?)\s*</td>\s*){7}</tr>', re.DOTALL)
|
||||
COLLAPSED_ROW_RE = re.compile(r'<table width=[^>]*>\s*(.*?)\s*</table>', re.DOTALL)
|
||||
TD_RE = re.compile(r'<td[^>]*>\s*(.*?)\s*</td>', re.DOTALL)
|
||||
TAG_RE = re.compile(r'<[^>]*>')
|
||||
SPACE_RE = re.compile(r'\s+')
|
||||
ATTACHMENT_RE = re.compile(r"\[\['cert_attachment_sid','([^']*)'\]\]")
|
||||
|
||||
|
||||
def remove_tags(text: str) -> str:
|
||||
return SPACE_RE.sub(' ', html.unescape(TAG_RE.sub(' ', text))).strip()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('query', type=str)
|
||||
args = parser.parse_args()
|
||||
query = {'PartnerCertSearchForm:pcs_' + q.split('=', 1)[0]: urllib.parse.unquote(q.split('=', 1)[-1]) for q in args.query.split('&')}
|
||||
|
||||
s = requests.Session()
|
||||
r = s.get(f'{URL}?menu_sid=5002')
|
||||
uri = ACTION_RE.findall(r.text)[0]
|
||||
hidden = {m[1]: m[2] for m in HIDDEN_RE.finditer(r.text)}
|
||||
|
||||
r = s.post(f'{BASE_URL}{uri}', data={
|
||||
**query,
|
||||
'PartnerCertSearchForm:button_search': 'Suche starten...',
|
||||
'PartnerCertSearchForm_SUBMIT': '1',
|
||||
'javax.faces.ViewState': hidden['javax.faces.ViewState'],
|
||||
})
|
||||
|
||||
result_table = r.text[r.text.find('<table'):r.text.rfind('</table>') + 8]
|
||||
uncollapsed_rows = [tuple(remove_tags(m[1])
|
||||
for m in TD_RE.finditer(row[0]))
|
||||
for row in UNCOLLAPSED_ROW_RE.finditer(result_table)]
|
||||
collapsed_rows = [[tuple(remove_tags((ATTACHMENT_RE.search(m[1]) or m)[1]) for m in TD_RE.finditer(row[1]))
|
||||
for row in ROW_RE.finditer(tbl[0])]
|
||||
for tbl in COLLAPSED_ROW_RE.finditer(result_table)]
|
||||
print('[')
|
||||
first = True
|
||||
for row, tbl in zip(uncollapsed_rows, collapsed_rows):
|
||||
meta = {}
|
||||
certificates = []
|
||||
for srow in tbl:
|
||||
if len(srow) == 1:
|
||||
[k,v] = srow[0].split(':', 1)
|
||||
meta[k.strip()] = v.strip()
|
||||
continue
|
||||
if len(srow) == 0:
|
||||
continue
|
||||
certificates.append({
|
||||
'nr': srow[0],
|
||||
'validFrom': '-'.join(reversed(srow[1].split('-'))),
|
||||
'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])}',
|
||||
})
|
||||
if not first:
|
||||
print(',', flush=True)
|
||||
print(' ', json.dumps({
|
||||
'idNr': row[0],
|
||||
'lfbisNr': row[1] or None,
|
||||
'name': row[2],
|
||||
'postalCode': row[3],
|
||||
'city': row[4],
|
||||
'address': row[5],
|
||||
'autorityName': meta['Kontrollstelle'],
|
||||
'productGroups': meta['Bereiche'],
|
||||
'certificates': certificates,
|
||||
}, ensure_ascii=False), end='')
|
||||
first = False
|
||||
print('\n]')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
36
www/organic/external/bioqs/attachments.php
vendored
Normal file
36
www/organic/external/bioqs/attachments.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
||||
header('Status: 405');
|
||||
header('Content-Length: 0');
|
||||
header('Allow: GET, HEAD');
|
||||
exit;
|
||||
}
|
||||
|
||||
$info = $_SERVER['PATH_INFO'];
|
||||
if ($info === '') {
|
||||
header('Status: 404');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
$certId = substr($info, 1);
|
||||
|
||||
$file = tmpfile();
|
||||
if (!$file) {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 0');
|
||||
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');
|
||||
exit;
|
||||
}
|
||||
|
||||
header('Content-Type: application/pdf');
|
||||
header('Content-Length: ' . filesize($filename));
|
||||
header('Content-Disposition: inline; filename="' . $pdfName . '"');
|
||||
readfile($filename);
|
43
www/organic/external/bioqs/operators.php
vendored
Normal file
43
www/organic/external/bioqs/operators.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
||||
header('Status: 405');
|
||||
header('Content-Length: 0');
|
||||
header('Allow: GET, HEAD');
|
||||
exit;
|
||||
}
|
||||
|
||||
$info = $_SERVER['PATH_INFO'];
|
||||
if ($info !== '') {
|
||||
header('Status: 404');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
|
||||
$query = [];
|
||||
if (isset($_GET['country'])) {
|
||||
$query[] = 'country=' . [
|
||||
'AT' => '1',
|
||||
'DE' => '2',
|
||||
][$_GET['country']] ?? '';
|
||||
}
|
||||
if (isset($_GET['postalCode'])) {
|
||||
$query[] = 'zipcode=' . urlencode($_GET['postalCode']);
|
||||
}
|
||||
if (isset($_GET['name'])) {
|
||||
$query[] = 'aname=' . urlencode($_GET['name']);
|
||||
}
|
||||
if (isset($_GET['idNr'])) {
|
||||
$query[] = 'clientcode=' . urlencode($_GET['idNr']);
|
||||
}
|
||||
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";
|
158
www/organic/external/easy-cert/operators.php
vendored
158
www/organic/external/easy-cert/operators.php
vendored
@@ -1,12 +1,5 @@
|
||||
<?php
|
||||
|
||||
$info = $_SERVER['PATH_INFO'];
|
||||
if ($info !== '') {
|
||||
header('Status: 404');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
||||
@@ -16,6 +9,122 @@ if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD
|
||||
exit;
|
||||
}
|
||||
|
||||
function jenc($data): string {
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
$info = $_SERVER['PATH_INFO'];
|
||||
if ($info !== '') {
|
||||
$parts = explode(':', substr($info, 1), 2);
|
||||
if (sizeof($parts) !== 2) {
|
||||
$url = "https://elwig.at/organic/external/easy-cert/operators?idNr=" . substr($info, 1);
|
||||
$s = curl_init($url);
|
||||
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
|
||||
if (($json = curl_exec($s)) === false) {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
$json = json_decode($json);
|
||||
if ($json->{'totalCount'} !== 1) {
|
||||
header('Status: 404');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
header('Status: 303');
|
||||
header('Location: ./' . $json->{'data'}[0]->{'db'} . ':' . $json->{'data'}[0]->{'id'});
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
$refDate = $_GET['referenceDate'] ?? null;
|
||||
if ($refDate !== null) {
|
||||
$refDate = explode('-', $refDate);
|
||||
$refDate = $refDate[2] . '.' . $refDate[1] . '.' . $refDate[0];
|
||||
}
|
||||
$url = "https://www.easy-cert.com/htm/suchresultat-detail.htm?sprache=de&db=" . urlencode($parts[0]) . "&id=" . urlencode(str_replace('-', '_', $parts[1])) . "&historyDate=" . urlencode($refDate);
|
||||
$s = curl_init($url);
|
||||
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
|
||||
if (($html = curl_exec($s)) === false) {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
|
||||
$html = preg_replace('/<!--.*?-->/s', ' ', $html);
|
||||
preg_match_all('@<tr>\s*<th[^>]*>([^<]*)</th>\s*<td[^>]*>([^<]*)</td>\s*</tr>@', $html, $matches, PREG_SET_ORDER);
|
||||
|
||||
$data = [];
|
||||
foreach ($matches as $m) {
|
||||
$data[$m[1]] = trim(html_entity_decode($m[2]));
|
||||
if ($data[$m[1]] === '') {
|
||||
$data[$m[1]] = null;
|
||||
}
|
||||
}
|
||||
$plzOrt = $data['PLZ / Ort'] ?? null;
|
||||
if ($plzOrt === null) {
|
||||
$postalCode = null;
|
||||
$city = null;
|
||||
} else {
|
||||
$p = explode(' ', $plzOrt, 2);
|
||||
$postalCode = trim($p[0]);
|
||||
$city = trim($p[1]);
|
||||
}
|
||||
|
||||
if ($data['Name'] === null) {
|
||||
header('Status: 404');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (preg_match('@name="historydate_input" value="([^"]*)"@', $html, $matches) === 1) {
|
||||
$refDate = $matches[1];
|
||||
$refDate = explode('.', $refDate);
|
||||
$refDate = $refDate[2] . '-' . $refDate[1] . '-' . $refDate[0];
|
||||
} else {
|
||||
$refDate = null;
|
||||
}
|
||||
|
||||
$certs = [];
|
||||
preg_match_all('@<tr>\s*<td nowrap>([^<]*)</td>\s*<td[^>]*>([^<]*)</td>\s*<td[^>]*>\s*([^<]*)\s*.*?</td>\s*<td [^\']*\'(https?://[^\']*)\'[^>]*>[^<]*</td>\s*</tr>@', $html, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $m) {
|
||||
$certs[] = [
|
||||
'nr' => $m[1],
|
||||
'validUntil' => implode('-', array_reverse(explode('.', $m[2]))),
|
||||
'type' => $m[3] === '' ? null : $m[3],
|
||||
'pdfUrl' => str_replace('http://', 'https://', $m[4]),
|
||||
];
|
||||
}
|
||||
|
||||
$labels = [];
|
||||
preg_match_all('@<tr>\s*<td>([^<]*)</td>\s*<td[^>]*>([^<]*)</td>\s*<td[^>]*>\s*([^<]*)\s*.*?</td>\s*<td [^\']*\'(https?://[^\']*)\'[^>]*>[^<]*</td>\s*</tr>@', $html, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $m) {
|
||||
$labels[] = [
|
||||
'nr' => $m[1],
|
||||
'validUntil' => implode('-', array_reverse(explode('.', $m[2]))),
|
||||
'type' => $m[3] === '' ? null : $m[3],
|
||||
'pdfUrl' => str_replace('http://', 'https://', $m[4]),
|
||||
];
|
||||
}
|
||||
|
||||
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) .
|
||||
'}';
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
$search_url = null;
|
||||
$url = null;
|
||||
$query_id = null;
|
||||
@@ -43,9 +152,10 @@ if (isset($_GET['queryId'])) {
|
||||
$country = $_GET['country'] ?? null;
|
||||
$postalCode = $_GET['postalCode'] ?? null;
|
||||
$name = $_GET['name'] ?? null;
|
||||
$idNr = $_GET['idNr'] ?? null;
|
||||
$renew = ($_GET['renew'] ?? 'false') === 'true';
|
||||
|
||||
$search_url = "https://www.easy-cert.com/htm/suchergebnis.htm?suchtyp=einfach&CountryCode=$country&PostalCode=$postalCode&Name=$name";
|
||||
$search_url = "https://www.easy-cert.com/htm/suchergebnis.htm?suchtyp=einfach&CountryCode=$country&PostalCode=$postalCode&Name=$name&CustomerNumber=$idNr";
|
||||
|
||||
if (!$renew && $cache = fopen('.cache.csv', 'r')) {
|
||||
while (($line = fgets($cache)) !== false) {
|
||||
@@ -111,15 +221,28 @@ $sed = [
|
||||
's/^/ /',
|
||||
's/}$/},/',
|
||||
];
|
||||
$replace = [
|
||||
'"DB":' => '"db":',
|
||||
'"Name":' => '"name":',
|
||||
'"PostalCode":' => '"postalCode":',
|
||||
'"Town":' => '"city":',
|
||||
'"CustomerNumber":' => '"idNr":',
|
||||
'"ID":' => '"id":',
|
||||
'"CountryCode":' => '"countryCode":',
|
||||
'"xx"' => 'null',
|
||||
'"XX"' => 'null',
|
||||
':""' => ':null',
|
||||
];
|
||||
$replaceSed = array_map(fn($v, $k): string => "s/$k/$v/", $replace, array_keys($replace));
|
||||
|
||||
header("Content-Type: application/json; charset=UTF-8");
|
||||
|
||||
echo '{"searchUrl":' . json_encode($search_url) .
|
||||
',"queryId":' . json_encode($query_id) .
|
||||
',"rawFileUrl":' . json_encode($url) .
|
||||
',"timestamp":' . json_encode(gmdate('Y-m-d\TH:i:s\Z', $timestamp)) .
|
||||
',"limit":' . json_encode($limit) .
|
||||
',"offset":' . json_encode($offset) . ",\"data\":[\n";
|
||||
echo '{"searchUrl":' . jenc($search_url) .
|
||||
',"queryId":' . jenc($query_id) .
|
||||
',"rawFileUrl":' . jenc($url) .
|
||||
',"timestamp":' . jenc(gmdate('Y-m-d\TH:i:s\Z', $timestamp)) .
|
||||
',"limit":' . jenc($limit) .
|
||||
',"offset":' . jenc($offset) . ",\"data\":[\n";
|
||||
|
||||
$fd_spec = [
|
||||
0 => ["pipe", "r"], // stdin
|
||||
@@ -138,14 +261,13 @@ $process = proc_open(
|
||||
"tee >(wc -l 1>&3) | " . // copy stdout into wc and write result into fd 3
|
||||
"tail -n +$offset | " . // apply offset
|
||||
($limit !== null ? " head -n $limit | " : "") . // optionally apply limit
|
||||
"sed '" . implode(';', $replaceSed) . "' | " . // replace strings in json
|
||||
"sed '\$s/.$//'"], // remove last comma of last line
|
||||
$fd_spec,
|
||||
$pipes
|
||||
);
|
||||
fclose($pipes[0]);
|
||||
while (($line = fgets($pipes[1])) !== false) {
|
||||
echo $line;
|
||||
}
|
||||
fpassthru($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
$stderr = stream_get_contents($pipes[2]);
|
||||
fclose($pipes[2]);
|
||||
@@ -153,4 +275,4 @@ $count = intval(trim(stream_get_contents($pipes[3])));
|
||||
fclose($pipes[3]);
|
||||
$return_value = proc_close($process);
|
||||
|
||||
echo '],"totalCount":' . json_encode($count) . "}\n";
|
||||
echo '],"totalCount":' . jenc($count) . "}\n";
|
||||
|
33
www/organic/external/lkv/operators.php
vendored
Normal file
33
www/organic/external/lkv/operators.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
||||
header('Status: 405');
|
||||
header('Content-Length: 0');
|
||||
header('Allow: GET, HEAD');
|
||||
exit;
|
||||
}
|
||||
|
||||
function jenc($data): string {
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
$info = $_SERVER['PATH_INFO'];
|
||||
if ($info !== '') {
|
||||
header('Status: 404');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
|
||||
echo "{\"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"@' \
|
||||
| sed 's@\s*",@",@g;s@:"\s*@:"@g'
|
||||
EOF);
|
||||
|
||||
echo "]}\n";
|
@@ -51,8 +51,20 @@ if (str_starts_with($info, '/certificates/')) {
|
||||
|
||||
exit;
|
||||
} else if ($info === '/authorities') {
|
||||
header('Content-Length: 0');
|
||||
header('Status: 501');
|
||||
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;
|
||||
exit;
|
||||
} else if (str_starts_with($info, '/authorities/')) {
|
||||
$code = $parts[2];
|
||||
|
269
www/organic/pdf.php
Normal file
269
www/organic/pdf.php
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'POST' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
||||
header('Status: 405');
|
||||
header('Content-Length: 0');
|
||||
header('Allow: GET, POST, HEAD');
|
||||
exit;
|
||||
}
|
||||
|
||||
$info = $_SERVER['PATH_INFO'];
|
||||
if ($info !== '') {
|
||||
header('Status: 404');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
$file = tmpfile();
|
||||
$headerfile = tmpfile();
|
||||
if (!$file || !$headerfile) {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
$filename = stream_get_meta_data($file)['uri'];
|
||||
$headerfilename = stream_get_meta_data($headerfile)['uri'];
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$stdin = fopen("php://input", "rb");
|
||||
while (!feof($stdin)) {
|
||||
if (($data = fread($stdin, 8192)) === false)
|
||||
break;
|
||||
fwrite($file, $data);
|
||||
}
|
||||
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 ($format === 'text') {
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
passthru("pdftotext -raw " . escapeshellarg($filename) . " -");
|
||||
} else if ($format === 'sig') {
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
passthru("pdfsig " . escapeshellarg($filename));
|
||||
} else if ($format === 'json') {
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
if (exec("pdftotext -raw " . escapeshellarg($filename) . " -", $text) === false) {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 0');
|
||||
exit;
|
||||
}
|
||||
$text = implode("\n", $text);
|
||||
exec("pdfsig " . escapeshellarg($filename), $sig);
|
||||
$sig = implode("\n", $sig);
|
||||
|
||||
$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]);
|
||||
}
|
||||
|
||||
$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, '• ')];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
echo "{\"type\":\"$authorityId\",\"lang\":\"de\",\"id\":" . jenc($certId) . ",\"nr\":" . jenc($certNr);
|
||||
echo ",\n \"operator\":{},\n \"authority\":{\"id\":" . jenc($authorityId) . "}}\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
echo "{\"type\":\"unknown\"}\n";
|
||||
} else {
|
||||
$headers = [];
|
||||
$status_code = null;
|
||||
foreach (explode("\n", file_get_contents($headerfilename)) as $line) {
|
||||
if (trim($line) === '') break;
|
||||
if ($status_code === null) {
|
||||
$status_code = intval(explode(' ', $line)[1]);
|
||||
if ($status_code !== 200)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
[$k,$v] = explode(':', $line, 2);
|
||||
$k = strtolower(trim($k));
|
||||
$v = trim($v);
|
||||
$headers[$k] = $v;
|
||||
}
|
||||
|
||||
if (str_starts_with($headers['content-type'], "application/pdf")) {
|
||||
header('Content-Type: application/pdf');
|
||||
$content_length = null;
|
||||
if (isset($headers['content-length'])) {
|
||||
$content_length = intval($headers['content-length']);
|
||||
header('Content-Length: ' . $headers['content-length']);
|
||||
}
|
||||
$parts = explode('/', $url);
|
||||
$realFilename = $parts[sizeof($parts) - 1];
|
||||
if (isset($headers['content-disposition'])) {
|
||||
preg_match('@filename="(.*?)"@', $headers['content-disposition'], $matches);
|
||||
$realFilename = $matches[1];
|
||||
}
|
||||
header('Content-Disposition: inline; filename="' . $realFilename . '"');
|
||||
fpassthru($file);
|
||||
} else {
|
||||
header('Status: 500');
|
||||
header('Content-Length: 0');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user