m m
Technical Support
m
Example of Reading a .QQT file using PHP
We are currently rewriting our entire web site. This page may be useful - but is not yet complete and may contain misleading or incomplete information or inoperative links. Please check back soon for the final version. Email support@datablox.com if you have questions.

Following is a simple example of ... 

 

<?php
 
class QQT {
 
  public $QBR_Account = 0;
  public $QBR_TranDoc = 1;
  public $QBR_TranLine = 2;
  public $QBR_Budget = 5;
  public $QBR_Class = 6;
  public $QBR_InvtItem = 7;
  public $QBR_PayrollItem = 8;
  public $QBR_Employee = 9;
  public $QBR_TimeLine = 13;
  public $QBR_CustJob = 14;
  public $QBR_CustType = 15;
  public $QBR_JobType = 16;
  public $QBR_CustMessage = 17;
  public $QBR_ShipVia = 18;
  public $QBR_PayMeth = 19;
  public $QBR_Terms = 20;
  public $QBR_Vendor = 21;
  public $QBR_VendType = 22;
  public $QBR_OtherName = 23;
  public $QBR_ToDoNote = 25;
  public $QBR_Company = 28;
  public $QBR_Settings = 29;
  public $QBR_TaxCode = 31;
  public $QBR_TranLink = 32;
  public $QBR_PriceLevel = 36;
  public $QBR_SalesTax = 37;
 
        // constants for all errors that can be returned
  public $QBERROR_FILE_DOESNT_EXIST = -30;
 
        // array of table names that correspond with table integer constant ids above
  public $aTableName = array();
 
        // array to array with: 'cnt', 'offs', 'last'
  private $aRec = array();      // each element is also an array
  private $fh;  // file handle
  private $sFilePath;  // string
 
  /*      from OfficeQ6 TLB
    function SetOptions(var sOptList: WideString): Integer;
    function ReadFile(var sFilePath: WideString; var sOptList: WideString): Integer;
    function RecordCount(nRecordType: Integer): Integer;
    function RecordN(nRecordType: Integer; nIndex: Integer; var sRecord: WideString): Integer;
    function RecordK(nRecordType: Integer; nKey: Integer; var sRecord: WideString): Integer;
    function FieldV(var sRecord: WideString; var sFieldName: WideString): WideString;
    function Diag(var sPick: WideString): WideString;
    function Done: Integer;
    function FieldACount(var sField: WideString): Integer; dispid 9;
    function FieldAV(var sField: WideString; nIndex: Integer): WideString; dispid 10;
  */
 
//----------------------------------------------------------------------------
public function __construct($sPath = '') {     // may or may not include the path
	$this->sFilePath = $sPath;
			// force structure and init counts and offsets for each record
			// type to -1
	for ($i = $this->QBR_Account;  $i <= $this->QBR_InvtLine;  $i++) {
		$this->aRec[$i] = array('cnt' => -1,  'offs' => -1, 'last' => -1);
	};
    $this->aTableName[$this->QBR_Account] = 'account';
    $this->aTableName[$this->QBR_TranDoc] = 'trandoc';
    $this->aTableName[$this->QBR_TranLine] = 'tranline';
    $this->aTableName[$this->QBR_Budget] = 'budget';
    $this->aTableName[$this->QBR_Class] = 'class';
    $this->aTableName[$this->QBR_InvtItem] = 'invtitem';
    $this->aTableName[$this->QBR_PayrollItem] = 'payrollitem';
    $this->aTableName[$this->QBR_Employee] = 'employee';
    $this->aTableName[$this->QBR_TimeLine] = 'timeline';
    $this->aTableName[$this->QBR_CustJob] = 'custjob';
    $this->aTableName[$this->QBR_CustType] = 'custtype';
    $this->aTableName[$this->QBR_JobType] = 'jobtype';
    $this->aTableName[$this->QBR_CustMessage] = 'custmessage';
    $this->aTableName[$this->QBR_ShipVia] = 'shipvia';
    $this->aTableName[$this->QBR_PayMeth] = 'paymeth';
    $this->aTableName[$this->QBR_Terms] = 'terms';
    $this->aTableName[$this->QBR_Vendor] = 'vendor';
    $this->aTableName[$this->QBR_VendType] = 'vendtype';
    $this->aTableName[$this->QBR_OtherName] = 'othername';
    $this->aTableName[$this->QBR_ToDoNote] = 'todonote';
    $this->aTableName[$this->QBR_Company] = 'company';
    $this->aTableName[$this->QBR_Settings] = 'settings';
    $this->aTableName[$this->QBR_TaxCode] = 'taxcode';
    $this->aTableName[$this->QBR_TranLink] = 'tranlink';
    $this->aTableName[$this->QBR_PriceLevel] = 'pricelevel';
    $this->aTableName[$this->QBR_SalesTax] = 'salestax';    
}
//----------------------------------------------------------------------------
//      remember to unset the object var so this will be called
public function __destruct() {
    fclose($this->fh);
}
 
//----------------------------------------------------------------------------
// return negative integer error code - 0 if no errors
//
public function ReadFile($sPath='', $sOptList) {
			// if specified during constructor - validate and read it
	if (strlen($this->sFilePath) > 0) {
        $sFile = $this->sFilePath;
	} else {
		if (strlen($sPath) > 0) {
            $sFile = $sPath;
                    // save as object variable too
            $this->sFilePath = $sPath;
		} else {
            return $this->QBERROR_FILE_DOESNT_EXIST;
		};
	};
    if (!file_exists($sFile)) {
        return $this->QBERROR_FILE_DOESNT_EXIST;
    }
    $this->pvReadRecBlock();
}
 
//----------------------------------------------------------------------------
private function pvReadRecBlock() {
    $this->fh = fopen($this->sFilePath, "rb");      // read binary
 
    fseek($this->fh, 8);            // 9th char in file is count of blocks to skip
    $ch = fread($this->fh, 1);      // ie '4' - decimal count of skip blocks
    $nSkip = ord($ch) - 48;
 
    $nOffs = $nSkip * 0x1000;
    fseek($this->fh, $nOffs);   // skip 4096 byte blocks
 
	for ($i = $this->QBR_Account;  $i <= $this->QBR_SalesTax;  $i++) {
 
                // 1st 4 is record count
        fseek($this->fh, $nOffs);   // skip 4096 byte blocks    
        $s = fread($this->fh, 4);
                // unpack unpacks to an assoc array
        $aa = unpack('V', $s);        
        $this->aRec[$i]["cnt"] = $aa[1];
 
                // 3rd 4 is offset
        fseek($this->fh, $nOffs + 8);   // skip 4096 byte blocks                    
        $s = fread($this->fh, 4);
 
        $aa = unpack('V', $s);
        $this->aRec[$i]["offs"] = $aa[1];
 
        $nOffs = $nOffs + 32;
	}    
}
 
//----------------------------------------------------------------------------
public function FieldV($sRecIn, $sFieldIn) {
    $sSearch = chr(0x1E) . $sFieldIn . chr(0x1C);
        // find 0 based pos of leftmost sSearch - F if not found
    $nPos = strpos($sRecIn, $sSearch);
            // skip name and delims
    $sValue = substr($sRecIn, $nPos + strlen($sFieldIn) + 2);
            // if it contains 1E, that's start of another field so cut it off
    $nPos = strpos($sValue, chr(0x1E));
    if ($nPos) {
        $sValue = substr($sValue, 0, $nPos);
    }
    return $sValue;
}
 
//----------------------------------------------------------------------------	
public function RecordCount($nRecType) {    
    $n = $this->aRec[$nRecType]['cnt'];
    return $n;
}
 
//----------------------------------------------------------------------------
//          & before $sRecord means 'pass by reference'
public function RecordN($nRecType, $nIndex, &$sRecord) {
    if ($nIndex == 0) {     // first record?
        fseek($this->fh, $this->aRec[$nRecType]['offs']);
    } else {    // $nIndex is not 0 - verify that $nIndex is increasing
        if ($nIndex < $this->aRec[$nRecType]['last']) {
            echo 'out of sequence';
            return -1;
        }
    }        
            // read next record number and save it in 'last' for comparison next time
    $s = fread($this->fh, 4);
    $aa = unpack('V', $s);
    $this->aRec[$nRecType]['last'] = $aa[1];
 
            // then read length of record in bytes
    $s = fread($this->fh, 4);
    $aa = unpack('V', $s);
 
            // then read actual bytes of record
    $sRecord = fread($this->fh, $aa[1]);
    return 0;
}
 
};
 
?>