?
Solved

php btrieve api example

Posted on 2010-01-11
5
Medium Priority
?
1,327 Views
Last Modified: 2013-12-25
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
Comment
Question by:bob_mechler
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
  • 2
5 Comments
 
LVL 34

Expert Comment

by:Beverley Portlock
ID: 26287343
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
 

Author Comment

by:bob_mechler
ID: 26287430
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
 
LVL 18

Expert Comment

by:mirtheil
ID: 26287434
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
 
LVL 18

Accepted Solution

by:
mirtheil earned 2000 total points
ID: 26288205
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
 

Author Closing Comment

by:bob_mechler
ID: 31675713
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

On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows the steps required to install WordPress on Azure. Web Apps, Mobile Apps, API Apps, or Functions, in Azure all these run in an App Service plan. WordPress is no exception and requires an App Service Plan and Database to install
This post looks at MongoDB and MySQL, and covers high-level MongoDB strengths, weaknesses, features, and uses from the perspective of an SQL user.
The viewer will learn how to dynamically set the form action using jQuery.
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …

800 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question