catching dbase_open error

Carbonecz
Carbonecz used Ask the Experts™
on
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!
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2011
Top Expert 2016

Commented:
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.
Most Valuable Expert 2011
Top Expert 2016

Commented:
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

Author

Commented:
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.
HTML5 and CSS3 Fundamentals

Build a website from the ground up by first learning the fundamentals of HTML5 and CSS3, the two popular programming languages used to present content online. HTML deals with fonts, colors, graphics, and hyperlinks, while CSS describes how HTML elements are to be displayed.

Most Valuable Expert 2011
Top Expert 2016
Commented:
In PHP throw is a term of art.  I think what you're seeing is called a Warning message.  You can suppress function-related messages with the @ sign pre-pended to the function call like this:

$dbase = @dbase_open ( $file_name, 0 );

Man page here: http://php.net/manual/en/language.operators.errorcontrol.php

Please be very careful if you choose to code that way.  You will still be at risk of function failures, but you will not get any diagnostic information at all.   Indiscriminate use of the @ message suppression is AntiPractice #5

Author

Commented:
At the end I used set_error_handler to do what I want with the message. Thanks!
Olaf DoschkeSoftware Developer

Commented:
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.
Most Valuable Expert 2011
Top Expert 2016

Commented:
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

Olaf DoschkeSoftware Developer

Commented:
>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.
Most Valuable Expert 2011
Top Expert 2016

Commented:

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial