{'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('@\s*]*>([^<]*)\s*]*>([^<]*)\s*@', $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('@\s*([^<]*)\s*]*>([^<]*)\s*]*>\s*([^<]*)\s*.*?\s*]*>[^<]*\s*@', $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('@\s*([^<]*)\s*]*>([^<]*)\s*]*>\s*([^<]*)\s*.*?\s*]*>[^<]*\s*@', $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";