Avatar of Carbonecz
Carbonecz
 asked on

catching dbase_open error

Hi,

I'm trying to read dbf files, but dbase_open can't read some of them because they're probably in a different format (some higher version of foxpro) so it exits with an error:

Warning: dbase_open() [function.dbase-open]: unable to open database

Open in new window

So, I found a package that can read them (PHPXBase). However it can only partially read some other formats that dbase_open reads fully.

Fatal error: cannot handle datatype

Open in new window

That's why I'm trying to catch error dbase_open throws and then try to read the file with phpxbase like this:

try {
    dbase_open ( $file_name, 0 );
}catch (Exception $e) {
    /* create a table object and open it */
    $table = new XBaseTable( $file_name );
    $table->open();

    /* print some header info */
    echo "version: ".$table->version."<br />";
    echo "foxpro: ".($table->foxpro?"yes":"no")."<br />";
    echo "modifyDate: ".date("r",$table->modifyDate)."<br />";
    echo "recordCount: ".$table->recordCount."<br />";
    echo "headerLength: ".$table->headerLength."<br />";
    echo "recordByteLength: ".$table->recordByteLength."<br />";
    echo "inTransaction: ".($table->inTransaction?"yes":"no")."<br />";
    echo "encrypted: ".($table->encrypted?"yes":"no")."<br />";
    echo "mdxFlag: ".ord($table->mdxFlag)."<br />";
    echo "languageCode: ".ord($table->languageCode)."<br />";

    /* html output */
    echo "<br /><table border=1>";

    /* print column names */
    echo "<tr>";
    foreach ($table->getColumns() as $i=>$c) {
            echo "<td>".$c->getName()." (".$c->getType()." ".$c->getLength().")</td>";
    }
    echo "</tr>";
        /* print records */
    while ($record=$table->nextRecord()) {
            echo "<tr>";
            foreach ($table->getColumns() as $i=>$c) {
                    echo "<td>".$record->getString($c)."</td>";
            }
            echo "</tr>";
    }
    echo "</table>";

    /* close the table */
    $table->close();
}

Open in new window

The problem is this doesn't work. It executes Try, shows me the "unable to open database" error and doesn't execute Catch at all.

Can you help me with this? Thanks!
PHP

Avatar of undefined
Last Comment
Ray Paseur

8/22/2022 - Mon
Ray Paseur

I don't think try{} catch{} is going to work here.  The user-contributed notes here indicate that this is a very old function, so it probably does not have the current design that would enable it to throw an exception.
http://php.net/manual/en/function.dbase-open.php

Try testing the return value from the function with an if() statement.  If you get FALSE, then you could proceed to try the alternate function.
Ray Paseur

Maybe something like this... Untested, but probably valid in principle.

<?php
error_reporting(E_ALL);

$dbase = dbase_open ( $file_name, 0 );
if (!$dbase)
{
    echo PHP_EOL . "dBase_open($file_name) Failed";
    echo PHP_EOL . "Trying XBaseTable next";
    $table = new XBaseTable( $file_name );
    $table->open();

    /* ETC */
}
else
{
    echo PHP_EOL . "Yay! dBase_open($file_name) Worked";
    
    /* ETC */
}

Open in new window

HTH, ~Ray
Carbonecz

ASKER
I don't think try{} catch{} is going to work here.  The user-contributed notes here indicate that this is a very old function, so it probably does not have the current design that would enable it to throw an exception.
http://php.net/manual/en/function.dbase-open.php

Try testing the return value from the function with an if() statement.  If you get FALSE, then you could proceed to try the alternate function.

That'd work but it still throws and shows an error which is annoying. I may drop support for old formats.
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
ASKER CERTIFIED SOLUTION
Ray Paseur

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
Carbonecz

ASKER
At the end I used set_error_handler to do what I want with the message. Thanks!
Olaf Doschke

If you have any way to get the first byte of the file, you can check, wether the DBF is a dbase type table or other.

Meanings of the values are as follows:
0x02   FoxBASE
0x03   FoxBASE+/Dbase III plus, no memo
0x30   Visual FoxPro
0x31   Visual FoxPro, autoincrement enabled
0x43   dBASE IV SQL table files, no memo
0x63   dBASE IV SQL system files, no memo
0x83   FoxBASE+/dBASE III PLUS, with memo
0x8B   dBASE IV with memo
0xCB   dBASE IV SQL table files, with memo
0xF5   FoxPro 2.x (or earlier) with memo
0xFB   FoxBASE

Check out some of the files working with dbase_open and the ones working with PHPXBase.  That'll work without Suppressing Messages with @.

On a Windows server you could also make use of the VFP OLEDB provider instead, see the example at the bottom of http://fox.wikis.com/wc.dll?Wiki~VFPOleDBProvider

Bye, Olaf.
Ray Paseur

any way to get the first byte of the file
Good idea and worth trying.  You might be able to use fopen(), fgets() to read the first record (I would avoid file_get_contents() or similar because of the overhead and risk of running out of memory).  Then you could use substr() to get the first byte and var_dump() to print it out.  Or you might find this useful to see the hex value of the first byte.

<?php // demo/hexdump.php
error_reporting(E_ALL);
echo '<pre>';

/*
 * Expand and display a variable in hexadecimal notation
 *
 * @param string $str The variable to expand and display
 * @return none (direct browser output)
 */
function hexdump($str, $br=PHP_EOL)
{
    if (empty($str)) return FALSE;

    // GET THE HEX BYTE VALUES IN A STRING
    $hex = str_split(implode(NULL, unpack('H*', $str)));

    // ALLOCATE BYTES INTO HI AND LO NIBBLES
    $hi  = NULL;
    $lo  = NULL;
    $mod = 0;
    foreach ($hex as $nib)
    {
        $mod++;
        $mod = $mod % 2;
        if ($mod)
        {
            $hi .= $nib;
        }
        else
        {
            $lo .= $nib;
        }
    }

    // SHOW THE SCALE, THE STRING AND THE HEX
    $num = substr('1...5...10...15...20...25...30...35...40...45...50...55...60...65...70...75...80...85...90...95..100..105..110..115..120..125..130', 0, strlen($str));
    echo $br . $num;
    echo $br . $str;
    echo $br . $hi;
    echo $br . $lo;
    echo $br;
}

// DEMONSTRATE IT WITH THE REQUEST ARGUMENT
hexdump($_GET['q']);

Open in new window

Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Olaf Doschke

>fgets() to read the first record
Just a side note: DBFs are not CSV files, nor similar. A record is not a line, instead it has fixed size, the first record is after a header with detail info and you might not have a CR or LF in all of a dbf file.

Nevertheless you can use fgets to read one byte only:
$handle = fopen($file_name, "r");
$byte = fgets($handle,1);

Open in new window

That'll be all you need to see what type of DBF you have. There are more than dbase foxbase, foxpro, eg clipper. So don't be surprised, if you also find not mentioned bytes/types. Create your own lists of working with dbase_open(), working with PHPXBase, or working with neither of them. Eg I'd guess Foxpro 2.x DBFs (F5) will work as dbase DBFs.

Bye, Olaf.
Ray Paseur