organic: Add pdf endpoint
This commit is contained in:
154
www/organic/external/easy-cert/operators.php
vendored
154
www/organic/external/easy-cert/operators.php
vendored
@@ -1,12 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$info = $_SERVER['PATH_INFO'];
|
|
||||||
if ($info !== '') {
|
|
||||||
header('Status: 404');
|
|
||||||
header('Content-Length: 0');
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Access-Control-Allow-Origin: *');
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
|
||||||
@@ -16,6 +9,122 @@ if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD
|
|||||||
exit;
|
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;
|
$search_url = null;
|
||||||
$url = null;
|
$url = null;
|
||||||
$query_id = null;
|
$query_id = null;
|
||||||
@@ -43,9 +152,10 @@ if (isset($_GET['queryId'])) {
|
|||||||
$country = $_GET['country'] ?? null;
|
$country = $_GET['country'] ?? null;
|
||||||
$postalCode = $_GET['postalCode'] ?? null;
|
$postalCode = $_GET['postalCode'] ?? null;
|
||||||
$name = $_GET['name'] ?? null;
|
$name = $_GET['name'] ?? null;
|
||||||
|
$idNr = $_GET['idNr'] ?? null;
|
||||||
$renew = ($_GET['renew'] ?? 'false') === 'true';
|
$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')) {
|
if (!$renew && $cache = fopen('.cache.csv', 'r')) {
|
||||||
while (($line = fgets($cache)) !== false) {
|
while (($line = fgets($cache)) !== false) {
|
||||||
@@ -111,15 +221,28 @@ $sed = [
|
|||||||
's/^/ /',
|
's/^/ /',
|
||||||
'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");
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
|
||||||
echo '{"searchUrl":' . json_encode($search_url) .
|
echo '{"searchUrl":' . jenc($search_url) .
|
||||||
',"queryId":' . json_encode($query_id) .
|
',"queryId":' . jenc($query_id) .
|
||||||
',"rawFileUrl":' . json_encode($url) .
|
',"rawFileUrl":' . jenc($url) .
|
||||||
',"timestamp":' . json_encode(gmdate('Y-m-d\TH:i:s\Z', $timestamp)) .
|
',"timestamp":' . jenc(gmdate('Y-m-d\TH:i:s\Z', $timestamp)) .
|
||||||
',"limit":' . json_encode($limit) .
|
',"limit":' . jenc($limit) .
|
||||||
',"offset":' . json_encode($offset) . ",\"data\":[\n";
|
',"offset":' . jenc($offset) . ",\"data\":[\n";
|
||||||
|
|
||||||
$fd_spec = [
|
$fd_spec = [
|
||||||
0 => ["pipe", "r"], // stdin
|
0 => ["pipe", "r"], // stdin
|
||||||
@@ -138,6 +261,7 @@ $process = proc_open(
|
|||||||
"tee >(wc -l 1>&3) | " . // copy stdout into wc and write result into fd 3
|
"tee >(wc -l 1>&3) | " . // copy stdout into wc and write result into fd 3
|
||||||
"tail -n +$offset | " . // apply offset
|
"tail -n +$offset | " . // apply offset
|
||||||
($limit !== null ? " head -n $limit | " : "") . // optionally apply limit
|
($limit !== null ? " head -n $limit | " : "") . // optionally apply limit
|
||||||
|
"sed '" . implode(';', $replaceSed) . "' | " . // replace strings in json
|
||||||
"sed '\$s/.$//'"], // remove last comma of last line
|
"sed '\$s/.$//'"], // remove last comma of last line
|
||||||
$fd_spec,
|
$fd_spec,
|
||||||
$pipes
|
$pipes
|
||||||
@@ -153,4 +277,4 @@ $count = intval(trim(stream_get_contents($pipes[3])));
|
|||||||
fclose($pipes[3]);
|
fclose($pipes[3]);
|
||||||
$return_value = proc_close($process);
|
$return_value = proc_close($process);
|
||||||
|
|
||||||
echo '],"totalCount":' . json_encode($count) . "}\n";
|
echo '],"totalCount":' . jenc($count) . "}\n";
|
||||||
|
182
www/organic/pdf.php
Normal file
182
www/organic/pdf.php
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = str_replace(' ', '+', $_GET['url']);
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($format === 'text') {
|
||||||
|
header('Content-Type: text/plain; charset=UTF-8');
|
||||||
|
passthru("curl -s '" . escapeshellarg($url) . "' | pdftotext -raw - -");
|
||||||
|
} else if ($format === 'json') {
|
||||||
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
|
$fd_spec = [
|
||||||
|
0 => ["pipe", "r"], // stdin
|
||||||
|
1 => ["pipe", "w"], // stdout
|
||||||
|
2 => ["pipe", "w"], // stderr
|
||||||
|
];
|
||||||
|
$process = proc_open(
|
||||||
|
['bash', '-c',
|
||||||
|
"curl -s " . escapeshellarg($url) . " | " .
|
||||||
|
"pdftotext -raw - -"],
|
||||||
|
$fd_spec,
|
||||||
|
$pipes
|
||||||
|
);
|
||||||
|
fclose($pipes[0]);
|
||||||
|
$text = stream_get_contents($pipes[1]);
|
||||||
|
fclose($pipes[1]);
|
||||||
|
$stderr = stream_get_contents($pipes[2]);
|
||||||
|
fclose($pipes[2]);
|
||||||
|
$return_value = proc_close($process);
|
||||||
|
|
||||||
|
if ($stderr !== '') {
|
||||||
|
header('Status: 500');
|
||||||
|
header('Content-Length: ' . strlen($stderr));
|
||||||
|
header('Content-Type: text/plain');
|
||||||
|
exit($stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
$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 = 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])));
|
||||||
|
|
||||||
|
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}\n";
|
||||||
|
} else {
|
||||||
|
echo "{\"type\":\"unknown\"}\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
header('Content-Type: application/pdf');
|
||||||
|
$s = curl_init($url);
|
||||||
|
curl_exec($s);
|
||||||
|
}
|
Reference in New Issue
Block a user