Files
elwig-www/www/organic/external/easy-cert/operators.php

281 lines
9.4 KiB
PHP

<?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 !== '') {
$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;
$timestamp = null;
$limit = $_GET['limit'] ?? null;
$offset = intval($_GET['offset'] ?? "0");
if ($limit === '') $limit = null;
if ($limit !== null) $limit = intval($limit);
if (isset($_GET['queryId'])) {
$query_id = $_GET['queryId'];
if ($cache = fopen('.cache.csv', 'r')) {
while (($line = fgets($cache)) !== false) {
$parts = explode(';', trim($line), 4);
$timestamp = intval($parts[0]);
if ($parts[1] !== $query_id) continue;
$url = $parts[2];
$search_url = $parts[3];
break;
}
fclose($cache);
}
} else {
$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&CustomerNumber=$idNr";
if (!$renew && $cache = fopen('.cache.csv', 'r')) {
while (($line = fgets($cache)) !== false) {
$parts = explode(';', trim($line), 4);
$timestamp = intval($parts[0]);
if (time() - $timestamp > 60 * 30) continue;
if ($parts[3] !== $search_url) continue;
$url = $parts[2];
$query_id = $parts[1];
break;
}
fclose($cache);
}
}
if ($url === null) {
$timestamp = time();
$s = curl_init($search_url);
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
$html = curl_exec($s);
preg_match_all('/id="control_([^"]*)" value="([^"]*)"/', $html, $matches, PREG_SET_ORDER);
$control = [];
foreach ($matches as $m) {
$control[$m[1]] = $m[2];
}
$query_id = $control['iniqueid'];
$server_count = $control['countserver'];
$lines = [];
for ($i = 0; $i < 30; $i++) {
sleep(1);
$s = curl_init("https://www.easy-cert.com/_includes/search/result_items.php");
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
curl_setopt($s, CURLOPT_HTTPHEADER, [
'Referer: https://www.easy-cert.com/htm/suchergebnis.htm',
'X-Requested-With: XMLHttpRequest',
'X-USE: 1dfd3nsdv234njsdf923masddj123n12l31lg28gsdf2k34',
]);
curl_setopt($s, CURLOPT_POSTFIELDS, "uniqueid=$query_id&countServer=$server_count");
$json = json_decode(curl_exec($s));
if ($json->{'count'} >= $server_count) {
$url = "https://www.easy-cert.com/" . str_replace('../', '', $json->{'filename'});
break;
}
}
if ($url !== null)
file_put_contents('.cache.csv', "$timestamp;$query_id;$url;$search_url\n", FILE_APPEND);
}
if ($url === null) {
header("Status: 500");
header("Content-Length: 0");
exit;
}
$sed = [
's/^.*"searchresults":\[//',
's/],.*$//',
's/},{/},\n {/g',
'/^$/d',
'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":' . 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
1 => ["pipe", "w"], // stdout
2 => ["pipe", "w"], // stderr
3 => ["pipe", "w"], // line count
];
$offset++;
$process = proc_open(
['bash', '-c',
"curl -s -N " . escapeshellarg($url) . " | " . // fetch data (silent and unbuffered)
"xxd -p | " . // convert to hex stream
"sed 's/7d2c7b/7d2c0a7b/g' | " . // roughly break up into lines (s/},{/},\n{/g)
"xxd -r -p | " . // convert to text stream
"sed '" . implode(';', $sed) . "' | " . // apply sed commands
"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;
}
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$count = intval(trim(stream_get_contents($pipes[3])));
fclose($pipes[3]);
$return_value = proc_close($process);
echo '],"totalCount":' . jenc($count) . "}\n";