Joakim Nygård Archive Linked About

Zend Framework Validator for Danish VAT Numbers

17 Mar 2009

Working on an as of yet unpublished startup, I needed a validator for the Danish CVR numbers issued as part of VAT registration. As the project is written in Zend Framework, I decided to implement the code as an extension of the Zend_Validate_Abstract and share it here.

The validation is based on the specification located at cvr.dk and involves a modulus 11 check on the 8th digit based on a weighted sum of the previous seven. Not particularly interesting but nice to have when working with Danish companies.

<?php
/**
 * Scienta Zend Additions
 *
 * @category   Scienta
 * @package    Scienta_Validate
 * @copyright  Copyright (c) 2008-2009 Joakim Nygård (http://jokke.dk)
 * @version    $Id$
 */

/** Zend_Validate_Abstract */
require_once 'Zend/Validate/Abstract.php';

/** Zend_Filter_Digits */
require_once 'Zend/Filter/Digits.php';

/**
 * A class for validating Danish CVR numbers based on modulo 11
 * @see http://www.cvr.dk/Site/Forms/CMS/DisplayPage.aspx?pageid=60
 * @category   Scienta
 * @package    Scienta_Validate
 * @copyright  Copyright (c) 2008-2009 Joakim Nygård (http://jokke.dk)
 */
class Scienta_Validate_Cvr extends Zend_Validate_Abstract
{
    const INVALID          = 'cvrInvalid';
    const INCORRECT_LENGTH = 'stringLengthNotRight';
    const NOT_DIGITS       = 'notDigits';

    protected $_messageTemplates = array(
        self::INVALID          => "'%value%' is not a valid CVR number",
        self::INCORRECT_LENGTH => "'%value%' does not contain 8 digits",
        self::NOT_DIGITS       => "'%value%' does not contain only digits",
    );

    protected $_cvrWeights = array(2, 7, 6, 5, 4, 3, 2);

    public function isValid($value)
    {
        $valueString = (string) $value;
        $this->_setValue($valueString);
    
        $filter = new Zend_Filter_Digits();
        if ($valueString !== $filter->filter($valueString)) {
            $this->_error(self::NOT_DIGITS);
            return false;
        }
        if (8 != strlen($valueString)) {
            $this->_error(self::INCORRECT_LENGTH);
            return false;
        }
    
        $sum = 0;
        foreach ($this->_cvrWeights as $i => $weight) {
            $sum += $valueString[$i] * $weight;
        }
        $remainder = $sum % 11;
		if($remainder==1){
		    $this->_error(self::INVALID);
		    return false;            
		}
		if($remainder==0)
		    $lastDigit = 0;
		else
		    $lastDigit = 11 - $remainder;
		
        $valid = ($valueString[7] == $lastDigit);

        if ($valid) {
            return true;
        } else {
            $this->_error(self::INVALID);
            return false;
        }
    }
}

Save the above to the file library/Scienta/Validate/Cvr.php with library being the directory containing the Zend framework. The class can then be used to test a number as follows:

$cvrValidator = new Scienta_Validate_Cvr();
if ($cvrValidator->isValid($proposedCvrNumber)) {
    ...
}

One case where testing is needed might be a Zend_Form, in which case the class is easily added as a validator on the appropriate element.