.dbf file format of dBASE: PHP parsing library

.dbf is a relational database format introduced in DOS database management system dBASE in 1982.

One .dbf file corresponds to one table and contains a series of headers, specification of fields, and a number of fixed-size records.

This page hosts a formal specification of .dbf file format of dBASE using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

PHP source code to parse .dbf file format of dBASE

Dbf.php

<?php
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

/**
 * .dbf is a relational database format introduced in DOS database
 * management system dBASE in 1982.
 * 
 * One .dbf file corresponds to one table and contains a series of headers,
 * specification of fields, and a number of fixed-size records.
 */

namespace {
    class Dbf extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Kaitai\Struct\Struct $_parent = null, \Dbf $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_header1 = new \Dbf\Header1($this->_io, $this, $this->_root);
            $this->_m__raw_header2 = $this->_io->readBytes((($this->header1()->lenHeader() - 12) - 1));
            $_io__raw_header2 = new \Kaitai\Struct\Stream($this->_m__raw_header2);
            $this->_m_header2 = new \Dbf\Header2($_io__raw_header2, $this, $this->_root);
            $this->_m_headerTerminator = $this->_io->readBytes(1);
            if (!($this->headerTerminator() == "\x0D")) {
                throw new \Kaitai\Struct\Error\ValidationNotEqualError("\x0D", $this->headerTerminator(), $this->_io(), "/seq/2");
            }
            $this->_m__raw_records = [];
            $this->_m_records = [];
            $n = $this->header1()->numRecords();
            for ($i = 0; $i < $n; $i++) {
                $this->_m__raw_records[] = $this->_io->readBytes($this->header1()->lenRecord());
                $_io__raw_records = new \Kaitai\Struct\Stream(end($this->_m__raw_records));
                $this->_m_records[] = new \Dbf\Record($_io__raw_records, $this, $this->_root);
            }
        }
        protected $_m_header1;
        protected $_m_header2;
        protected $_m_headerTerminator;
        protected $_m_records;
        protected $_m__raw_header2;
        protected $_m__raw_records;
        public function header1() { return $this->_m_header1; }
        public function header2() { return $this->_m_header2; }
        public function headerTerminator() { return $this->_m_headerTerminator; }
        public function records() { return $this->_m_records; }
        public function _raw_header2() { return $this->_m__raw_header2; }
        public function _raw_records() { return $this->_m__raw_records; }
    }
}

namespace Dbf {
    class Header2 extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dbf $_parent = null, \Dbf $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            if ($this->_root()->header1()->dbaseLevel() == 3) {
                $this->_m_headerDbase3 = new \Dbf\HeaderDbase3($this->_io, $this, $this->_root);
            }
            if ($this->_root()->header1()->dbaseLevel() == 7) {
                $this->_m_headerDbase7 = new \Dbf\HeaderDbase7($this->_io, $this, $this->_root);
            }
            $this->_m_fields = [];
            $i = 0;
            while (!$this->_io->isEof()) {
                $this->_m_fields[] = new \Dbf\Field($this->_io, $this, $this->_root);
                $i++;
            }
        }
        protected $_m_headerDbase3;
        protected $_m_headerDbase7;
        protected $_m_fields;
        public function headerDbase3() { return $this->_m_headerDbase3; }
        public function headerDbase7() { return $this->_m_headerDbase7; }
        public function fields() { return $this->_m_fields; }
    }
}

namespace Dbf {
    class Field extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dbf\Header2 $_parent = null, \Dbf $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_name = \Kaitai\Struct\Stream::bytesToStr(\Kaitai\Struct\Stream::bytesTerminate($this->_io->readBytes(11), 0, false), "ASCII");
            $this->_m_datatype = $this->_io->readU1();
            $this->_m_dataAddress = $this->_io->readU4le();
            $this->_m_length = $this->_io->readU1();
            $this->_m_decimalCount = $this->_io->readU1();
            $this->_m_reserved1 = $this->_io->readBytes(2);
            $this->_m_workAreaId = $this->_io->readU1();
            $this->_m_reserved2 = $this->_io->readBytes(2);
            $this->_m_setFieldsFlag = $this->_io->readU1();
            $this->_m_reserved3 = $this->_io->readBytes(8);
        }
        protected $_m_name;
        protected $_m_datatype;
        protected $_m_dataAddress;
        protected $_m_length;
        protected $_m_decimalCount;
        protected $_m_reserved1;
        protected $_m_workAreaId;
        protected $_m_reserved2;
        protected $_m_setFieldsFlag;
        protected $_m_reserved3;
        public function name() { return $this->_m_name; }
        public function datatype() { return $this->_m_datatype; }
        public function dataAddress() { return $this->_m_dataAddress; }
        public function length() { return $this->_m_length; }
        public function decimalCount() { return $this->_m_decimalCount; }
        public function reserved1() { return $this->_m_reserved1; }
        public function workAreaId() { return $this->_m_workAreaId; }
        public function reserved2() { return $this->_m_reserved2; }
        public function setFieldsFlag() { return $this->_m_setFieldsFlag; }
        public function reserved3() { return $this->_m_reserved3; }
    }
}

namespace Dbf {
    class Header1 extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dbf $_parent = null, \Dbf $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_version = $this->_io->readU1();
            $this->_m_lastUpdateY = $this->_io->readU1();
            $this->_m_lastUpdateM = $this->_io->readU1();
            $this->_m_lastUpdateD = $this->_io->readU1();
            $this->_m_numRecords = $this->_io->readU4le();
            $this->_m_lenHeader = $this->_io->readU2le();
            $this->_m_lenRecord = $this->_io->readU2le();
        }
        protected $_m_dbaseLevel;
        public function dbaseLevel() {
            if ($this->_m_dbaseLevel !== null)
                return $this->_m_dbaseLevel;
            $this->_m_dbaseLevel = ($this->version() & 7);
            return $this->_m_dbaseLevel;
        }
        protected $_m_version;
        protected $_m_lastUpdateY;
        protected $_m_lastUpdateM;
        protected $_m_lastUpdateD;
        protected $_m_numRecords;
        protected $_m_lenHeader;
        protected $_m_lenRecord;
        public function version() { return $this->_m_version; }
        public function lastUpdateY() { return $this->_m_lastUpdateY; }
        public function lastUpdateM() { return $this->_m_lastUpdateM; }
        public function lastUpdateD() { return $this->_m_lastUpdateD; }
        public function numRecords() { return $this->_m_numRecords; }
        public function lenHeader() { return $this->_m_lenHeader; }
        public function lenRecord() { return $this->_m_lenRecord; }
    }
}

namespace Dbf {
    class HeaderDbase3 extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dbf\Header2 $_parent = null, \Dbf $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_reserved1 = $this->_io->readBytes(3);
            $this->_m_reserved2 = $this->_io->readBytes(13);
            $this->_m_reserved3 = $this->_io->readBytes(4);
        }
        protected $_m_reserved1;
        protected $_m_reserved2;
        protected $_m_reserved3;
        public function reserved1() { return $this->_m_reserved1; }
        public function reserved2() { return $this->_m_reserved2; }
        public function reserved3() { return $this->_m_reserved3; }
    }
}

namespace Dbf {
    class HeaderDbase7 extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dbf\Header2 $_parent = null, \Dbf $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_reserved1 = $this->_io->readBytes(2);
            if (!($this->reserved1() == "\x00\x00")) {
                throw new \Kaitai\Struct\Error\ValidationNotEqualError("\x00\x00", $this->reserved1(), $this->_io(), "/types/header_dbase_7/seq/0");
            }
            $this->_m_hasIncompleteTransaction = $this->_io->readU1();
            $this->_m_dbaseIvEncryption = $this->_io->readU1();
            $this->_m_reserved2 = $this->_io->readBytes(12);
            $this->_m_productionMdx = $this->_io->readU1();
            $this->_m_languageDriverId = $this->_io->readU1();
            $this->_m_reserved3 = $this->_io->readBytes(2);
            if (!($this->reserved3() == "\x00\x00")) {
                throw new \Kaitai\Struct\Error\ValidationNotEqualError("\x00\x00", $this->reserved3(), $this->_io(), "/types/header_dbase_7/seq/6");
            }
            $this->_m_languageDriverName = $this->_io->readBytes(32);
            $this->_m_reserved4 = $this->_io->readBytes(4);
        }
        protected $_m_reserved1;
        protected $_m_hasIncompleteTransaction;
        protected $_m_dbaseIvEncryption;
        protected $_m_reserved2;
        protected $_m_productionMdx;
        protected $_m_languageDriverId;
        protected $_m_reserved3;
        protected $_m_languageDriverName;
        protected $_m_reserved4;
        public function reserved1() { return $this->_m_reserved1; }
        public function hasIncompleteTransaction() { return $this->_m_hasIncompleteTransaction; }
        public function dbaseIvEncryption() { return $this->_m_dbaseIvEncryption; }
        public function reserved2() { return $this->_m_reserved2; }
        public function productionMdx() { return $this->_m_productionMdx; }
        public function languageDriverId() { return $this->_m_languageDriverId; }
        public function reserved3() { return $this->_m_reserved3; }
        public function languageDriverName() { return $this->_m_languageDriverName; }
        public function reserved4() { return $this->_m_reserved4; }
    }
}

namespace Dbf {
    class Record extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dbf $_parent = null, \Dbf $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_deleted = $this->_io->readU1();
            $this->_m_recordFields = [];
            $n = count($this->_root()->header2()->fields());
            for ($i = 0; $i < $n; $i++) {
                $this->_m_recordFields[] = $this->_io->readBytes($this->_root()->header2()->fields()[$i]->length());
            }
        }
        protected $_m_deleted;
        protected $_m_recordFields;
        public function deleted() { return $this->_m_deleted; }
        public function recordFields() { return $this->_m_recordFields; }
    }
}

namespace Dbf {
    class DeleteState {
        const FALSE = 32;
        const TRUE = 42;
    }
}