PHP - VIES VAT number validation (European VAT-ID)

Technik
PHP - VIES VAT number validation (European VAT-ID)

If you are hosting a webshop or any admin system with B2B clients, you might be also collecting VAT-IDs of your commercial clients. Usually you would like them to enter valid ids. Moreover, for legal reasons, you have to check this number in certain cases. Lets automate this step!

First of all, you can check the number manually at the official address of the service (http://ec.europa.eu/taxation_customs/vies/) or my much more user friendly and free VAT ID Checking Tool.

However, it would be perfect, if your system could validate the VAT-ID every time, a new customer creates an account on your website, automatically, for example. Well this can be done pretty easily in PHP. The EU offers a so called WSDL (Web Services Description Language) Endpoint, which can be easily called with PHPs internal SoapClient Extension.

As of 2021 I will provide two examples. One modern version written in Symfony and a plain PHP version for other CMSs or Frameworks.

Symfony

In your controller, simply add this code. As of the popularity of JavaScript, this returns a JSON Object, when called with by the api path /vatid/api?vatid={VATID}.

/**
 * @Route("/vatid", name="vatid", methods={"GET"})
 * @Route("/vatid/api", name="vatid_api", methods={"GET"}, requirements={"_format": "json"}, defaults={"_format": "json"})
 * @return Response
 */
public function vatid(Request $request, $_format = 'html'): Response
{

    if ($_format == 'json') {

        $vatid = $request->query->getAlnum('vatid'); // The EU Vat Id

        try {
            // a valid vat id consists of an alpha country code and up to 12 alphanumeric characters
            $vatidRegex = "/^[a-z]{2}[a-z0-9]{0,12}$/i";

            if (preg_match($vatidRegex, $vatid) !== 1) {
                throw new InvalidVatIdException('Invalid Vat Id Format');
            }

            $client = new \SoapClient("https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl");

            // using checkVatApprox() as it tends to return a bit more information than checkVat()
            $params = [
                'countryCode' => substr($vatid, 0, 2),
                'vatNumber' => substr($vatid, 2),
            ];
            $result = $client->checkVatApprox($params);

        } catch (InvalidVatIdException $exception) {
            $result = [
                'error' => 'Ungültiges UID Nummer Format'
            ];
        } catch (\SoapFault $exception) {
            $result = [
                'error' => 'Der USt.-Service der EU scheint gerade nicht erreichbar zu sein'
            ];
        }

        // you may now check for $result->isValid, or you can print all the result fields by using print_r($result)
        // in this case, i simply return a json
        $response = new Response();
        $response->setContent(json_encode($result));

        return $response;
    }

    return $this->render('tools/vatid.html.twig', [
    ]);

}

...
class InvalidVatIdException extends \Exception
{

}

Then simply use JavaScripts fetch api to get the Data:

fetch(`/vatid/api?vatid=${vatid}`,
{
    headers: {
        'Content-Type': 'application/json'
    }
})
.then(response => {
    if (response.status === 200) {
        return response.json();
    } else {
        alert('Ungültiger Status')
    }
})
.then(data => {
    if (data.error) {
        alert(data.error);
    } else {
        // do something with your result data
        console.log(data);

    }
})

Easy legacy PHP Version

This is an simplified version without any dependencies. Simply copy and paste and manually edit the $vatid to your desired VAT ID.

try {
    $vatid = "ATU123456789";

    $vatid = preg_replace("/[^a-zA-Z0-9]]/", "", $vatid); // remove non alphanum characters

    // a valid vat id consists of an alpha country code and up to 12 alphanumeric characters
    $vatidRegex = "/^[a-z]{2}[a-z0-9]{0,12}$/i";

    if (preg_match($vatidRegex, $vatid) !== 1) {
        throw new \Exception('Invalid Vat Id Format');
    }

    $client = new \SoapClient("https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl");

    // using checkVatApprox() as it tends to return a bit more information than checkVat()
    $params = [
        'countryCode' => substr($vatid, 0, 2),
        'vatNumber' => substr($vatid, 2),
    ];
    $result = $client->checkVatApprox($params);

    if ($result->valid) {
        // VAT ID is valid
        echo 'Valid';
        print_r($result);
    } else {
        // VAT ID is NOT valid
        echo 'Invalid';
    }

} catch (\Exception $exception) {
    echo 'Es ist ein Fehler aufgetreten!';
}
Permalink: https://to.ptmr.io/1n7OZ9B