Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1370
  • Last Modified:

php btrieve api example

I have an app running in Pervasive 10 where I know the layout and don't need or want DDF'S. Can these files be read using PHP? This would be for Web development.
0
bob_mechler
Asked:
bob_mechler
  • 2
  • 2
1 Solution
 
Beverley PortlockCommented:
Btrieve is not specifically mentioned in the list of database extensions for PHP so I guess that ODBC might be your best bet.

http://us2.php.net/manual/en/refs.database.php

Neither PEAR nor PECL seems to possess a Btrieve package either.
0
 
bob_mechlerProgrammerAuthor Commented:
The btrieve api access method is really just calls to wbtrv32.dll. So the next question might be, can php make calls to the functions in DLL's that are located in the same directory. They wouldn't have to be managed code would they, since this is basically a CGI setup with php-cgi.exe added as the handler for php in IIS.

Bob
0
 
mirtheilCommented:
I compiled a proof of concept PHP Extension for Windows to call the Btrieve API years ago.  It was compiled with PHP 4.  It worked as a proof of concept but abandoned it in favor of ODBC.  

I'll see if I can dig it up.  It wasn't difficult.  The biggest issue was actually the security rights.  
0
 
mirtheilCommented:
Here's what I've got:

/* include standard header */ /* you will need to include this in all of your php extension projects*/ 
#include "php.h"
#include <string.h>
#include "btrapi.h"
#include "btrconst.h"

#define FILE1_NAME "c:\\pvsw\\samples\\sample.btr"
#define FILE2_NAME "c:\\pvsw\\samples\\sample2.btr"
#define MY_THREAD_ID        50
#define EXIT_WITH_ERROR     1

#if defined(_MSC_VER) || defined(__WATCOMC__)
    #pragma pack(1)
#endif
/***************************************************************************
  Type definitions for Client ID and version Structures
****************************************************************************/
typedef struct
{
  BTI_CHAR networkAndNode[12];
  BTI_CHAR applicationID[2];
  BTI_WORD threadID;
} CLIENT_ID;

typedef struct
{
  BTI_SINT  Version;
  BTI_SINT  Revision;
  BTI_CHAR  MKDEId;
} VERSION_STRUCT;

/***************************************************************************
  Definition of record from 'sample.btr'
****************************************************************************/
typedef struct
{
  BTI_LONG  ID;
  BTI_CHAR  FirstName[16];
  BTI_CHAR  LastName[26];
  BTI_CHAR  Street[31];
  BTI_CHAR  City[31];
  BTI_CHAR  State[3];
  BTI_CHAR  Zip[11];
  BTI_CHAR  Country[21];
  BTI_CHAR  Phone[14];
} PERSON_STRUCT;

/***************************************************************************
  Type definitions for Stat/Create structure
****************************************************************************/
typedef struct
{
  BTI_SINT recLength;
  BTI_SINT pageSize;
  BTI_SINT indexCount;
  BTI_CHAR reserved[4];
  BTI_SINT flags;
  BTI_BYTE dupPointers;
  BTI_BYTE notUsed;
  BTI_SINT allocations;
} FILE_SPECS;

typedef struct
{
  BTI_SINT position;
  BTI_SINT length;
  BTI_SINT flags;
  BTI_CHAR reserved[4];
  BTI_CHAR type;
  BTI_CHAR null;
  BTI_CHAR notUsed[2];
  BTI_BYTE manualKeyNumber;
  BTI_BYTE acsNumber;
} KEY_SPECS;

typedef struct
{
  FILE_SPECS fileSpecs;
  KEY_SPECS  keySpecs[5];
} FILE_CREATE_BUF;

/***************************************************************************
  Structure type definitions for Get Next Extended operation
****************************************************************************/
typedef struct
{
  BTI_SINT    descriptionLen;
  BTI_CHAR    currencyConst[2];
  BTI_SINT    rejectCount;
  BTI_SINT    numberTerms;
} GNE_HEADER;

typedef struct
{
  BTI_CHAR    fieldType;
  BTI_SINT    fieldLen;
  BTI_SINT    fieldOffset;
  BTI_CHAR    comparisonCode;
  BTI_CHAR    connector;
  BTI_CHAR value[3];
} TERM_HEADER;

typedef struct
{
  BTI_SINT    maxRecsToRetrieve;
  BTI_SINT    noFieldsToRetrieve;
} RETRIEVAL_HEADER;

typedef struct
{
  BTI_SINT    fieldLen;
  BTI_SINT    fieldOffset;
} FIELD_RETRIEVAL_HEADER;

typedef struct
{
  GNE_HEADER              gneHeader;
  TERM_HEADER             term1;
  TERM_HEADER             term2;
  RETRIEVAL_HEADER        retrieval;
  FIELD_RETRIEVAL_HEADER  recordRet;
} PRE_GNE_BUFFER;

typedef struct
{
  BTI_SINT      recLen;
  BTI_LONG      recPos;
  PERSON_STRUCT personRecord;
} RETURNED_REC;

typedef struct
{
  BTI_SINT      numReturned;
  RETURNED_REC  recs[20];
} POST_GNE_BUFFER;

typedef union
{
  PRE_GNE_BUFFER  preBuf;
  POST_GNE_BUFFER postBuf;
} GNE_BUFFER, BTI_FAR* GNE_BUFFER_PTR;

/* restore structure packing */
#if defined(_MSC_VER) || defined(__WATCOMC__)
	#pragma pack()
#endif

/* All the functions that will be exported (available) must be declared */ 
ZEND_FUNCTION(hello_world); 
PHP_MINFO_FUNCTION(btrievephp);

/* Just a basic int to be used as a counter*/ 
int i;

/* function list so that the Zend engine will know whats here */ 
zend_function_entry btrievephp_functions[] = { ZEND_FE(hello_world, NULL) {NULL, NULL, NULL} };

/* module information */ 
zend_module_entry btrievephp_module_entry = { STANDARD_MODULE_HEADER, "BtrievePHP", btrievephp_functions, NULL, NULL, NULL, NULL, PHP_MINFO(btrievephp), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES };

#if COMPILE_DL_BTRIEVEPHP_MOD 
ZEND_GET_MODULE(btrievephp) 
#endif

PHP_MINFO_FUNCTION(btrievephp) { 
	php_info_print_table_start(); 
	php_info_print_table_row(2, "Btrieve Extension", "This is a Btrieve Extension."); 
	php_info_print_table_end(); }

/*ZEND_FUNCTION(hello_world) 
{
	for(i=0;i<5;i++) 
	{ 
		zend_zend_printf("Hello World<br>"); 
	} 
} */

ZEND_FUNCTION(hello_world)
{
  /* Btrieve function parameters */
  BTI_BYTE posBlock1[128];
  BTI_BYTE posBlock2[128];
  BTI_BYTE dataBuf[255];
  BTI_WORD dataLen;
  BTI_BYTE keyBuf1[255];
  BTI_BYTE keyBuf2[255];
  BTI_WORD keyNum = 0;

  BTI_BYTE btrieveLoaded = FALSE;
  BTI_LONG personID;
  BTI_BYTE file1Open = FALSE;
  BTI_BYTE file2Open = FALSE;
  BTI_SINT status;
  BTI_SINT getStatus = -1;
  BTI_SINT i;
  BTI_SINT posCtr;

  CLIENT_ID       clientID;
  VERSION_STRUCT  versionBuffer[3];
  FILE_CREATE_BUF fileCreateBuf;
  GNE_BUFFER_PTR  gneBuffer;
  PERSON_STRUCT   personRecord;

  zend_printf("**************** Btrieve C/C++ Interface Demo ****************<br><br><br>\n<br>\n");

  /* set up the Client ID */
  memset(clientID.networkAndNode, 0, sizeof(clientID.networkAndNode));
  memcpy(clientID.applicationID, "MT", 2);  /* must be greater than "AA" */
  clientID.threadID = MY_THREAD_ID;

  memset(versionBuffer, 0, sizeof(versionBuffer));
  dataLen = sizeof(versionBuffer);

  status = BTRVID(
              B_VERSION,
              posBlock1,
              &versionBuffer,
              &dataLen,
              keyBuf1,
              keyNum,
              (BTI_BUFFER_PTR)&clientID);

  if (status == B_NO_ERROR)
  {
    zend_printf("Btrieve Versions returned are: <br>\n");
    for (i = 0; i < 3; i++) {
      if (versionBuffer[i].Version != 0)
      {
        zend_printf("   %d.%d %c<br>\n", versionBuffer[i].Version,
                versionBuffer[i].Revision,
                versionBuffer[i].MKDEId);
      }
    }
    zend_printf("<br>\n");
    btrieveLoaded = TRUE;
  }
  else
  {
    zend_printf("Btrieve B_VERSION status = %d<br>\n", status);
    if (status != B_RECORD_MANAGER_INACTIVE)
    {
      btrieveLoaded = TRUE;
    }
  }

  /* clear buffers */
  if (status == B_NO_ERROR)
  {
    memset(dataBuf, 0, sizeof(dataBuf));
    memset(keyBuf1, 0, sizeof(keyBuf1));
    memset(keyBuf2, 0, sizeof(keyBuf2));
  }

  /* open sample.btr */
  if (status == B_NO_ERROR)
  {

    strcpy((BTI_CHAR *)keyBuf1, FILE1_NAME);
    strcpy((BTI_CHAR *)keyBuf2, FILE2_NAME);

    keyNum  = 0;
    dataLen = 0;

    status = BTRVID(
                B_OPEN,
                posBlock1,
                dataBuf,
                &dataLen,
                keyBuf1,
                keyNum,
                (BTI_BUFFER_PTR)&clientID);

    zend_printf("Btrieve B_OPEN status (sample.btr) = %d<br>\n", status);
    if (status == B_NO_ERROR)
    {
      file1Open = TRUE;
    }
  }

  /* get the record with key 0 = 263512477 using B_GET_EQUAL */
  if (status == B_NO_ERROR)
  {
    memset(&personRecord, 0, sizeof(personRecord));
    dataLen = sizeof(personRecord);
    personID = 263512477;    /* this is really a social security number */
    *(BTI_LONG BTI_FAR *)&keyBuf1[0] = personID;
    keyNum = 0;

    status = BTRVID(
                B_GET_EQUAL,
                posBlock1,
                &personRecord,
                &dataLen,
                keyBuf1,
                keyNum,
                (BTI_BUFFER_PTR)&clientID);

    zend_printf("Btrieve B_GET_EQUAL status = %d<br>\n", status);
    if (status == B_NO_ERROR)
    {
      zend_printf("<br>\n");
      zend_printf("The retrieved record is:<br>\n");
      zend_printf("ID:      %ld<br>\n", personRecord.ID);
      zend_printf("Name:    %s %s<br>\n", personRecord.FirstName,
                                 personRecord.LastName);
      zend_printf("Street:  %s<br>\n", personRecord.Street);
      zend_printf("City:    %s<br>\n", personRecord.City);
      zend_printf("State:   %s<br>\n", personRecord.State);
      zend_printf("Zip:     %s<br>\n", personRecord.Zip);
      zend_printf("Country: %s<br>\n", personRecord.Country);
      zend_printf("Phone:   %s<br>\n", personRecord.Phone);
      zend_printf("<br>\n");
    }
  }

  /* perform a stat operation to populate the create buffer */
  memset(&fileCreateBuf, 0, sizeof(fileCreateBuf));
  dataLen = sizeof(fileCreateBuf);
  keyNum = (BTI_WORD)-1;

  status = BTRVID(B_STAT,
                posBlock1,
                &fileCreateBuf,
                &dataLen,
                keyBuf1,
                keyNum,
                (BTI_BUFFER_PTR)&clientID);

  if (status == B_NO_ERROR)
  {
    /* create and open sample2.btr */
    keyNum = 0;
    dataLen = sizeof(fileCreateBuf);
    status = BTRVID(B_CREATE,
                  posBlock2,
                  &fileCreateBuf,
                  &dataLen,
                  keyBuf2,
                  keyNum,
                  (BTI_BUFFER_PTR)&clientID);

    zend_printf("Btrieve B_CREATE status = %d<br>\n", status);
  }

  if (status == B_NO_ERROR)
  {
    keyNum = 0;
    dataLen = 0;

    status = BTRVID(
                B_OPEN,
                posBlock2,
                dataBuf,
                &dataLen,
                keyBuf2,
                keyNum,
                (BTI_BUFFER_PTR)&clientID);

    zend_printf("Btrieve B_OPEN status (sample2.btr) = %d<br>\n", status);
    if (status == B_NO_ERROR)
    {
      file2Open = TRUE;
    }
  }

  /* now extract data from the original file, insert into new one */
  if (status == B_NO_ERROR)
  {
    /* getFirst to establish currency */
    keyNum = 2; /* STATE-CITY index */
    memset(&personRecord, 0, sizeof(personRecord));
    memset(&keyBuf2[0], 0, sizeof(keyBuf2));
    dataLen = sizeof(personRecord);

    getStatus = BTRVID(
                   B_GET_FIRST,
                   posBlock1,
                   &personRecord,
                   &dataLen,
                   keyBuf1,
                   keyNum,
                   (BTI_BUFFER_PTR)&clientID);

    zend_printf("Btrieve B_GET_FIRST status (sample.btr) = %d<br><br><br>\n<br>\n", getStatus);
  }

  gneBuffer = malloc(sizeof(GNE_BUFFER));
  if (gneBuffer == NULL)
  {
     zend_printf("Insufficient memory to allocate buffer");
    return;
  }
  memset(gneBuffer, 0, sizeof(GNE_BUFFER));
  memcpy(&gneBuffer->preBuf.gneHeader.currencyConst[0], "UC", 2);
  while (getStatus == B_NO_ERROR)
  {
    gneBuffer->preBuf.gneHeader.rejectCount = 0;
    gneBuffer->preBuf.gneHeader.numberTerms = 2;
    posCtr = sizeof(GNE_HEADER);

    /* fill in the first condition */
    gneBuffer->preBuf.term1.fieldType = 11;
    gneBuffer->preBuf.term1.fieldLen = 3;
    gneBuffer->preBuf.term1.fieldOffset = 108;
    gneBuffer->preBuf.term1.comparisonCode = 1;
    gneBuffer->preBuf.term1.connector = 2;
    memcpy(&gneBuffer->preBuf.term1.value[0], "TX", 2);
    posCtr += sizeof(TERM_HEADER);

    /* fill in the second condition */
    gneBuffer->preBuf.term2.fieldType = 11;
    gneBuffer->preBuf.term2.fieldLen = 3;
    gneBuffer->preBuf.term2.fieldOffset = 108;
    gneBuffer->preBuf.term2.comparisonCode = 1;
    gneBuffer->preBuf.term2.connector = 0;
    memcpy(&gneBuffer->preBuf.term2.value[0], "CA", 2);
    posCtr += sizeof(TERM_HEADER);

    /* fill in the projection header to retrieve whole record */
    gneBuffer->preBuf.retrieval.maxRecsToRetrieve = 20;
    gneBuffer->preBuf.retrieval.noFieldsToRetrieve = 1;
    posCtr += sizeof(RETRIEVAL_HEADER);
    gneBuffer->preBuf.recordRet.fieldLen = sizeof(PERSON_STRUCT);
    gneBuffer->preBuf.recordRet.fieldOffset = 0;
    posCtr += sizeof(FIELD_RETRIEVAL_HEADER);
    gneBuffer->preBuf.gneHeader.descriptionLen = posCtr;

    dataLen = sizeof(GNE_BUFFER);
    getStatus = BTRVID(
                   B_GET_NEXT_EXTENDED,
                   posBlock1,
                   gneBuffer,
                   &dataLen,
                   keyBuf1,
                   keyNum,
                   (BTI_BUFFER_PTR)&clientID);

     zend_printf("Btrieve B_GET_NEXT_EXTENDED status = %d<br>\n", getStatus);

    /* Get Next Extended can reach end of file and still return some records */
    if ((getStatus == B_NO_ERROR) || (getStatus == B_END_OF_FILE))
    {
      zend_printf("GetNextExtended returned %d records.<br>\n", gneBuffer->postBuf.numReturned);
      for (i = 0; i < gneBuffer->postBuf.numReturned; i++)
      {
        dataLen = sizeof(PERSON_STRUCT);
        memcpy(dataBuf, &gneBuffer->postBuf.recs[i].personRecord, dataLen);
        status = BTRVID(
                    B_INSERT,
                    posBlock2,
                    dataBuf,
                    &dataLen,
                    keyBuf2,
                    -1,   /* no currency change */
                    (BTI_BUFFER_PTR)&clientID);
      }
      zend_printf("Inserted %d records in new file, status = %d<br><br><br>\n<br>\n", gneBuffer->postBuf.numReturned, status);
    }
    memset(gneBuffer, 0, sizeof(GNE_BUFFER));
    memcpy(&gneBuffer->preBuf.gneHeader.currencyConst[0], "EG", 2);
  }

  free(gneBuffer);
  gneBuffer = NULL;

  /* close open files */
  if (file1Open)
  {
    dataLen = 0;

    status = BTRVID(
                B_CLOSE,
                posBlock1,
                dataBuf,
                &dataLen,
                keyBuf1,
                keyNum,
                (BTI_BUFFER_PTR)&clientID);

    zend_printf("Btrieve B_CLOSE status (sample.btr) = %d<br>\n", status);
  }

  if (file2Open)
  {
    dataLen = 0;

    status = BTRVID(
                B_CLOSE,
                posBlock2,
                dataBuf,
                &dataLen,
                keyBuf2,
                keyNum,
                (BTI_BUFFER_PTR)&clientID);

    zend_printf("Btrieve B_CLOSE status (sample2.btr) = %d<br>\n", status);
  }

  /**********************************************************************
     ISSUE THE BTRIEVE STOP OPERATION - For multi-tasking environments,
     such as MS Windows, OS2, and NLM, 'stop' frees all Btrieve resources
     for this client.  In DOS and Extended DOS, it removes the Btrieve
     engine from memory, which we choose not to do in this example.  In
     multi-tasking environments, the engine will not unload on 'stop'
     unless it has no more clients.
  ***********************************************************************/
  #if !defined(BTI_DOS) && !defined(BTI_DOS_32R) && \
  !defined(BTI_DOS_32B) && !defined(BTI_DOS_32P)
  if (btrieveLoaded)
  {
    dataLen = 0;
    status = BTRVID(B_STOP, posBlock1, dataBuf, &dataLen, keyBuf1, keyNum,
             (BTI_BUFFER_PTR)&clientID);
    zend_printf("Btrieve STOP status = %d<br>\n", status);
    if (status != B_NO_ERROR)
    {
       status = EXIT_WITH_ERROR;
    }
  }
  #endif

  return;
}

Open in new window

0
 
bob_mechlerProgrammerAuthor Commented:
Thanks for rummaging through your code closet. This gives me what I need to get started making a PHP extension for PHP and btrieve. Now I need to get adept at PHP extensions and how to apply them in a IIS environment.

Bob
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now