check("DE263136143","SE556459933901","Wind River AB","Kista","Finlandsgatan 52","16493","ja"); * echo $this->check("DE263136143","HU12925481","TGIF KFT.","Egerszaloki","3394","Szechenyiu","ja"); * echo $this->check("DE263136143","SE556459933901","jkjk","Kista","Finlandsgatan 52","16493","ja"); */ class USTID { /** * online formular @https://evatr.bff-online.de/eVatR/index_html#Einfach_Ergebnis * * @var string API base * @var string API endpoint */ const BASE = 'https://evatr.bff-online.de'; const ENDPOINT = 'evatrRPC'; /** * just for downward compatibility, * the classes 'Adresse' and the 'erpAPI' * use that public value to access the * response data * * @var array */ var $answer = array( 'UstId_1' => '', 'UstId_2' => '', 'ErrorCode' => '', 'Druck' => '', 'Erg_PLZ' => '', 'Ort' => '', 'Datum' => '', 'PLZ' => '', 'Erg_Ort' => '', 'Uhrzeit' => '', 'Erg_Name' => '', 'Gueltig_ab' => '', 'Gueltig_bis' => '', 'Strasse' => '', 'Firmenname' => '', 'Erg_Str' => '', 'ErrorMSG' => '', 'OK' => '', ); /** * the required GET-parameter, * leave blank if field is not necessary, * but don't remove it from the request. * @see: https://evatr.bff-online.de/eVatR/xmlrpc/schnittstelle * * @var array */ private $_data = array( 'UstId_1' => '', // Ihre deutsche USt-IdNr. 'UstId_2' => '', // Anzufragende ausländische USt-IdNr. 'Firmenname' => '', // Name der anzufragenden Firma einschl. Rechtsform 'Ort' => '', // Ort der anzufragenden Firma 'PLZ' => '', // Postleitzahl der anzufragenden Firma 'Strasse' => '', // Strasse und Hausnummer der anzufragenden Firma, 'Druck' => 'nein' // ja = mit amtlicher Bestätigungsmitteilung ); /** * @see https://evatr.bff-online.de/eVatR/xmlrpc/codes * @var array $_errorCodes */ private $_errorCodes = array( /* * my own * Kein gültiger Fehlercode vom Finanzamt-Server erhalten. */ 100 => 'Es wurde keine Antwort vom Finanzamt-Server erhalten. Nur in der Zeit zwischen 05:00 Uhr und 23:00 Uhr sind abfragen möglich', 101 => 'Es wurde eine Fehlerhafte Antwort vom Finanzamt-Server erhalten', /* * API's status/error codes */ 200 => 'Die angefragte USt-IdNr. ist gültig.', 201 => 'Die angefragte USt-IdNr. ist ungültig.', 202 => 'Die angefragte USt-IdNr. ist ungültig. Sie ist nicht in der Unternehmerdatei des betreffenden EU-Mitgliedstaates registriert. (Hinweis: Ihr Geschäftspartner kann seine gültige USt-IdNr. bei der für ihn zuständigen Finanzbehörde in Erfahrung bringen. Möglicherweise muss er einen Antrag stellen, damit seine USt-IdNr. in die Datenbank aufgenommen wird.)', 203 => 'Die angefragte USt-IdNr. ist ungültig. Sie ist erst ab dem {{Gueltig_ab}} gültig.', 204 => 'Die angefragte USt-IdNr. ist ungültig. Sie war im Zeitraum von {{Gueltig_ab}} bis {{Gueltig_bis}} gültig.', 205 => 'Ihre Anfrage kann derzeit durch den angefragten EU-Mitgliedstaat oder aus anderen Gründen nicht beantwortet werden.', 206 => 'Ihre deutsche USt-IdNr. ist ungültig. Eine Bestätigungsanfrage ist daher nicht möglich.', 207 => 'Ihnen wurde die deutsche USt-IdNr. ausschliesslich zu Zwecken der Besteuerung des innergemeinschaftlichen Erwerbs erteilt. Sie sind somit nicht berechtigt, Bestätigungsanfragen zu stellen.', 208 => 'Für die von Ihnen angefragte USt-IdNr. läuft gerade eine Anfrage von einem anderen Nutzer. Eine Bearbeitung ist daher nicht möglich. Bitte versuchen Sie es später noch einmal.', 209 => 'Die angefragte USt-IdNr. ist ungültig. Sie entspricht nicht dem Aufbau der für diesen EU-Mitgliedstaat gilt.', 210 => 'Die angefragte USt-IdNr. ist ungültig. Sie entspricht nicht den Prüfziffernregeln die für diesen EU-Mitgliedstaat gelten.', 211 => 'Die angefragte USt-IdNr. ist ungültig. Sie enthält unzulässige Zeichen (wie z.B. Leerzeichen oder Punkt oder Bindestrich usw.).', 212 => 'Die angefragte USt-IdNr. ist ungültig. Sie enthält ein unzulässiges Länderkennzeichen.', 213 => 'Die Abfrage einer deutschen USt-IdNr. ist nicht möglich.', 214 => 'Ihre deutsche USt-IdNr. ist fehlerhaft. Sie beginnt mit \'DE\' gefolgt von 9 Ziffern.', 215 => 'Ihre Anfrage enthält nicht alle notwendigen Angaben für eine einfache Bestätigungsanfrage (Ihre deutsche USt-IdNr. und die ausl. USt-IdNr.).', 216 => 'Ihre Anfrage enthält nicht alle notwendigen Angaben für eine qualifizierte Bestätigungsanfrage. (Ihre deutsche USt-IdNr., die ausl. USt-IdNr., Firmenname einschl. Rechtsform und Ort).', 217 => 'Bei der Verarbeitung der Daten aus dem angefragten EU-Mitgliedstaat ist ein Fehler aufgetreten.', 218 => 'Eine qualifizierte Bestätigung ist zur Zeit nicht möglich.', 219 => 'Bei der Durchführung der qualifizierten Bestätigungsanfrage ist ein Fehler aufgetreten. Die angefragte USt-IdNr. ist gültig.', 220 => 'Bei der Anforderung der amtlichen Bestätigungsmitteilung ist ein Fehler aufgetreten. Sie werden kein Schreiben erhalten.', 221 => 'Die Anfragedaten enthalten nicht alle notwendigen Parameter oder einen ungültigen Datentyp.', 222 => 'Die angefragte USt-IdNr. ist gültig.', 999 => 'Eine Bearbeitung Ihrer Anfrage ist zurzeit nicht möglich. Bitte versuchen Sie es später noch einmal.' ); /** * the last error message * @var string */ private $_error = ''; /** * @param string $ust1 your UST ID * @param string $ust2 requested UST ID * @param string $firmenname * @param string $ort * @param string $strasse * @param string $plz * @param string $druck * @param $onlinefehler * @return int * * return values: * 1: ok, * -1: invalid/wrong response, * -2: curl error */ function check($ust1, $ust2, $firmenname, $ort, $strasse, $plz, $druck = "nein", &$onlinefehler) { $this->set('UstId_1', $ust1); $this->set('UstId_2', $ust2); $this->set('Firmenname', $firmenname); $this->set('Ort', $ort); $this->set('Strasse', $strasse); $this->set('PLZ', $plz); $this->set('Druck', $druck); /* * we could use $response = $this->send(); * send() returns only false or the response. * To detect the reason of an error, don't use it. */ $url = $this->buildQueryURL(); $response = $this->curl($url); if ($response == false) { /** * curl failed, * */ $onlinefehler = $this->_error; return -2; } $response = $this->convertXML2Array($response); $this->answer = $response; $this->_error = $response['ErrorMSG']; $onlinefehler = $this->_error; return $response['OK'] == true ? 1 : -1; } /** * from erpAPI (class.erpapi.php) to simplify that class * from first version of USTID, still unused? */ function checkAndSendMailIfWrong() { // Job: implement // this method was empty } /** * just for downward compatibility, * the class 'Adresse' use that method * to get the error code message * * @param $code * @return string */ function errormessages($code) { return $this->generateErrorMsg($code); } /** * return the error code message * alias for errormessages * * @param $code * @return string */ public function getErrorMsg($code) { return $this->generateErrorMsg($code); } /** * create the full url and send the request * * @param array $args * @return mixed */ public function send($args = array()) { if (is_array($args) && !empty($args)) { foreach ($args as $key => $value) { $this->set($key, $value); } } if (!empty($this->_error)) { /** * on error, don't send the request, * let the user change the settings */ return false; } $url = $this->buildQueryURL(); $response = $this->curl($url); if ($response == false) { /** * curl failed, * */ return false; } $response = $this->convertXML2Array($response); $this->answer = $response; $this->_error = $response['ErrorMSG']; return true; } /** * just a little helper to reset the request */ public function reset() { foreach ($this->_data as $key => $_) { $this->_data[$key] = ''; } } /** * set an GET parameter, * only the keys from $_data array are allowed, * only string values are allowed * * @param string $key * @param string $value * @return bool */ public function set($key, $value) { if (!is_string($value)) { $this->_error = 'Invalid value type given'; return false; } if (!is_string($key)) { $this->_error = 'Invalid key type given'; return false; } $keys = array_keys($this->_data); if (!in_array($key, $keys)) { $this->_error = "Key [{$key}] is not allowed"; return false; } $this->_data[$key] = $value; return true; } /** * build the query url and reset the config * * @return string */ private function buildQueryURL() { $args = $this->formatData($this->_data); $args = http_build_query($args); $url = self::BASE . '/' . self::ENDPOINT . '?' . $args; $this->reset(); return $url; } /** * before curl, reformat the data. * validate the 'Druck' value, * remove blanks from the UstId * * @param array $data * @return array */ private function formatData($data) { if (!$data['Druck'] == 'ja') { /* * the 'Druck' value was not set to 'ja', * so empty that value */ $data['Druck'] = ''; } foreach (array('UstId_1', 'UstId_2') as $key) { /* * unzulässige Zeichen (wie z.B. Leerzeichen oder Punkt oder Bindestrich usw.) */ $value = $data[$key]; $value = str_replace(" ", "", $value); $value = str_replace(".", "", $value); $value = str_replace("-", "", $value); $data[$key] = $value; } return $data; } /** * curl the given url * @param $url * @return mixed */ private function curl($url) { $ch = curl_init($url); curl_setopt_array($ch, array( CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSLVERSION => 6, CURLOPT_POST => false, CURLOPT_RETURNTRANSFER => true, )); $result = curl_exec($ch); if (!$result) { $this->_error = 'curl error: ' . curl_error($ch); return false; } $info = curl_getinfo($ch); curl_close($ch); $httpCode = $info['http_code']; if ($httpCode != 200 && $httpCode != 222) { $this->_error = 'Konnte Finanzamt-Server nicht erreichen (HTTP status code: ' . $httpCode . ')'; return false; } return $result; } /** * convert the xml to array * * @param $xml * @return array */ private function convertXML2Array($xml) { if (!$xml) { return array( 'ErrorMSG' => $this->_errorCodes[100], 'ErrorCode' => 100 ); } $xml = simplexml_load_string($xml); if ($xml === false) { return array( 'ErrorMSG' => $this->_errorCodes[101], 'ErrorCode' => 101 ); } $response = array(); if (isset($xml->param)) { foreach ($xml->param as $param) { if (!isset($param->value->array->data->value)) { continue; } $key = (string)$param->value->array->data->value[0]->string; $value = (string)$param->value->array->data->value[1]->string; $response[$key] = is_numeric($value) ? ((int)$value) : $value; } } $response = $this->extendResponse($response); return $response; } /** * extend the 'ErrorMSG' and the 'OK' field * * @param array $response * @return array */ private function extendResponse($response) { $response = (array)$response; /** * let's add the error msg from the error codes 'table' */ $response['ErrorMSG'] = 'Kein gültiger Fehlercode vom Finanzamt-Server erhalten.'; if (array_key_exists('ErrorCode', $response)) { $error = (int)$response['ErrorCode']; $response['ErrorMSG'] = $this->generateErrorMsg($error, $response); $response['OK'] = $response['ErrorCode'] == 200; } else { $response['ErrorMSG'] = 'Kein gültiger Fehlercode vom Finanzamt-Server erhalten.'; $response['OK'] = false; } return $response; } /** * @param $code * @param $env * @return string */ private function generateErrorMsg($code, $env = array()) { if (!array_key_exists($code, $this->_errorCodes)) { return 'Kein gültiger Fehlercode vom Finanzamt-Server erhalten.'; } $msg = $this->_errorCodes[$code]; if (empty($env) || !is_array($env)) { $rep = array('{{' => '(Siehe Feld: ', '}}' => ')'); return strtr($msg, $rep); } /** * extracts the placeholders in the msg string. * E.g.: Sie war im Zeitraum von {{Gueltig_ab}} bis {{Gueltig_bis}} gültig. * converts to: * array( * 0 => array( * 0 => '{{Gueltig_ab}}' * 1 => '{{Gueltig_bis}}' * ) * 1 => array( * 0 => Gueltig_ab * 1 => Gueltig_bis * ) * ) */ preg_match_all("/\{\{([^}]+)\}\}/", $msg, $keys); /* * filter empty results: */ $keys = array_filter($keys); /* * for each key in the extract, replace the string */ $rep = array(); if (is_array($keys) && count($keys) == 2) { foreach ($keys[1] as $key) { if (!array_key_exists($key, $env)) { continue; } $rep['{{' . $key . '}}'] = $env[$key]; } $msg = strtr($msg, $rep); } return $msg; } }