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:
Can you help me with this? Thanks!
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
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
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();
}
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!
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 */
}
HTH, ~Ray
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.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
At the end I used set_error_handler to do what I want with the message. Thanks!
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.
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.
any way to get the first byte of the fileGood 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']);
>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:
Bye, Olaf.
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);
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.
Man page here:
http://php.net/manual/en/function.fgets.php
http://php.net/manual/en/function.fgets.php
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.