3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
6 * The PEAR DB driver for PHP's dbase extension
7 * for interacting with dBase databases
11 * LICENSE: This source file is subject to version 3.0 of the PHP license
12 * that is available through the world-wide-web at the following URI:
13 * http://www.php.net/license/3_0.txt. If you did not receive a copy of
14 * the PHP License and are unable to obtain it through the web, please
15 * send a note to license@php.net so we can mail you a copy immediately.
19 * @author Tomas V.V. Cox <cox@idecnet.com>
20 * @author Daniel Convissor <danielc@php.net>
21 * @copyright 1997-2007 The PHP Group
22 * @license http://www.php.net/license/3_0.txt PHP License 3.0
23 * @version CVS: $Id: dbase.php,v 1.45 2007/09/21 13:40:41 aharvey Exp $
24 * @link http://pear.php.net/package/DB
28 * Obtain the DB_common class so it can be extended from
30 require_once 'DB/common.php';
33 * The methods PEAR DB uses to interact with PHP's dbase extension
34 * for interacting with dBase databases
36 * These methods overload the ones declared in DB_common.
40 * @author Tomas V.V. Cox <cox@idecnet.com>
41 * @author Daniel Convissor <danielc@php.net>
42 * @copyright 1997-2007 The PHP Group
43 * @license http://www.php.net/license/3_0.txt PHP License 3.0
44 * @version Release: 1.7.14RC1
45 * @link http://pear.php.net/package/DB
47 class DB_dbase extends DB_common
52 * The DB driver type (mysql, oci8, odbc, etc.)
55 var $phptype = 'dbase';
58 * The database syntax variant to be used (db2, access, etc.), if any
61 var $dbsyntax = 'dbase';
64 * The capabilities of this DB implementation
66 * The 'new_link' element contains the PHP version that first provided
67 * new_link support for this DBMS. Contains false if it's unsupported.
69 * Meaning of the 'limit' element:
70 * + 'emulate' = emulate with fetch row by number
71 * + 'alter' = alter the query
76 var $features = array(
83 'transactions' => false,
87 * A mapping of native error codes to DB error codes
90 var $errorcode_map = array(
94 * The raw database connection created by PHP
100 * The DSN information for connecting to a database
107 * A means of emulating result resources
110 var $res_row = array();
113 * The quantity of results so far
115 * For emulating result resources.
122 * Maps dbase data type id's to human readable strings
124 * The human readable values are based on the output of PHP's
125 * dbase_get_header_info() function.
128 * @since Property available since Release 1.7.0
143 * This constructor calls <kbd>$this->DB_common()</kbd>
156 * Connect to the database and create it if it doesn't exist
158 * Don't call this method directly. Use DB::connect() instead.
160 * PEAR DB's dbase driver supports the following extra DSN options:
161 * + mode An integer specifying the read/write mode to use
162 * (0 = read only, 1 = write only, 2 = read/write).
163 * Available since PEAR DB 1.7.0.
164 * + fields An array of arrays that PHP's dbase_create() function needs
165 * to create a new database. This information is used if the
166 * dBase file specified in the "database" segment of the DSN
167 * does not exist. For more info, see the PHP manual's
168 * {@link http://php.net/dbase_create dbase_create()} page.
169 * Available since PEAR DB 1.7.0.
171 * Example of how to connect and establish a new dBase file if necessary:
173 * require_once 'DB.php';
176 * 'phptype' => 'dbase',
177 * 'database' => '/path/and/name/of/dbase/file',
180 * array('a', 'N', 5, 0),
181 * array('b', 'C', 40),
182 * array('c', 'C', 255),
183 * array('d', 'C', 20),
188 * 'portability' => DB_PORTABILITY_ALL,
191 * $db = DB::connect($dsn, $options);
192 * if (PEAR::isError($db)) {
193 * die($db->getMessage());
197 * @param array $dsn the data source name
198 * @param bool $persistent should the connection be persistent?
200 * @return int DB_OK on success. A DB_Error object on failure.
202 function connect($dsn, $persistent = false)
204 if (!PEAR::loadExtension('dbase')) {
205 return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
209 if ($dsn['dbsyntax']) {
210 $this->dbsyntax = $dsn['dbsyntax'];
214 * Turn track_errors on for entire script since $php_errormsg
215 * is the only way to find errors from the dbase extension.
217 @ini_set('track_errors', 1);
220 if (!file_exists($dsn['database'])) {
221 $this->dsn['mode'] = 2;
222 if (empty($dsn['fields']) || !is_array($dsn['fields'])) {
223 return $this->raiseError(DB_ERROR_CONNECT_FAILED,
225 'the dbase file does not exist and '
226 . 'it could not be created because '
227 . 'the "fields" element of the DSN '
228 . 'is not properly set');
230 $this->connection = @dbase_create($dsn['database'],
232 if (!$this->connection) {
233 return $this->raiseError(DB_ERROR_CONNECT_FAILED,
235 'the dbase file does not exist and '
236 . 'the attempt to create it failed: '
240 if (!isset($this->dsn['mode'])) {
241 $this->dsn['mode'] = 0;
243 $this->connection = @dbase_open($dsn['database'],
245 if (!$this->connection) {
246 return $this->raiseError(DB_ERROR_CONNECT_FAILED,
258 * Disconnects from the database server
260 * @return bool TRUE on success, FALSE on failure
262 function disconnect()
264 $ret = @dbase_close($this->connection);
265 $this->connection = null;
272 function &query($query = null)
274 // emulate result resources
275 $this->res_row[(int)$this->result] = 0;
276 $tmp = new DB_result($this, $this->result++);
284 * Places a row from the result set into the given array
286 * Formating of the array and the data therein are configurable.
287 * See DB_result::fetchInto() for more information.
289 * This method is not meant to be called directly. Use
290 * DB_result::fetchInto() instead. It can't be declared "protected"
291 * because DB_result is a separate object.
293 * @param resource $result the query result resource
294 * @param array $arr the referenced array to put the data in
295 * @param int $fetchmode how the resulting array should be indexed
296 * @param int $rownum the row number to fetch (0 = first row)
298 * @return mixed DB_OK on success, NULL when the end of a result set is
299 * reached or on failure
301 * @see DB_result::fetchInto()
303 function fetchInto($result, &$arr, $fetchmode, $rownum = null)
305 if ($rownum === null) {
306 $rownum = $this->res_row[(int)$result]++;
308 if ($fetchmode & DB_FETCHMODE_ASSOC) {
309 $arr = @dbase_get_record_with_names($this->connection, $rownum);
310 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
311 $arr = array_change_key_case($arr, CASE_LOWER);
314 $arr = @dbase_get_record($this->connection, $rownum);
319 if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
320 $this->_rtrimArrayValues($arr);
322 if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
323 $this->_convertNullArrayValuesToEmpty($arr);
332 * Deletes the result set and frees the memory occupied by the result set.
334 * This method is a no-op for dbase, as there aren't result resources in
335 * the same sense as most other database backends.
337 * @param resource $result PHP's query result resource
339 * @return bool TRUE on success, FALSE if $result is invalid
341 * @see DB_result::free()
343 function freeResult($result)
352 * Gets the number of columns in a result set
354 * This method is not meant to be called directly. Use
355 * DB_result::numCols() instead. It can't be declared "protected"
356 * because DB_result is a separate object.
358 * @param resource $result PHP's query result resource
360 * @return int the number of columns. A DB_Error object on failure.
362 * @see DB_result::numCols()
364 function numCols($foo)
366 return @dbase_numfields($this->connection);
373 * Gets the number of rows in a result set
375 * This method is not meant to be called directly. Use
376 * DB_result::numRows() instead. It can't be declared "protected"
377 * because DB_result is a separate object.
379 * @param resource $result PHP's query result resource
381 * @return int the number of rows. A DB_Error object on failure.
383 * @see DB_result::numRows()
385 function numRows($foo)
387 return @dbase_numrecords($this->connection);
391 // {{{ quoteBoolean()
394 * Formats a boolean value for use within a query in a locale-independent
397 * @param boolean the boolean value to be quoted.
398 * @return string the quoted string.
399 * @see DB_common::quoteSmart()
400 * @since Method available since release 1.7.8.
402 function quoteBoolean($boolean) {
403 return $boolean ? 'T' : 'F';
410 * Returns information about the current database
412 * @param mixed $result THIS IS UNUSED IN DBASE. The current database
413 * is examined regardless of what is provided here.
414 * @param int $mode a valid tableInfo mode
416 * @return array an associative array with the information requested.
417 * A DB_Error object on failure.
419 * @see DB_common::tableInfo()
420 * @since Method available since Release 1.7.0
422 function tableInfo($result = null, $mode = null)
424 if (function_exists('dbase_get_header_info')) {
425 $id = @dbase_get_header_info($this->connection);
426 if (!$id && $php_errormsg) {
427 return $this->raiseError(DB_ERROR,
433 * This segment for PHP 4 is loosely based on code by
434 * Hadi Rusiah <deegos@yahoo.com> in the comments on
435 * the dBase reference page in the PHP manual.
437 $db = @fopen($this->dsn['database'], 'r');
439 return $this->raiseError(DB_ERROR_CONNECT_FAILED,
447 $line = fread($db, 32);
449 $line = fread($db, 32);
450 if (substr($line, 0, 1) == chr(13)) {
453 $pos = strpos(substr($line, 0, 10), chr(0));
454 $pos = ($pos == 0 ? 10 : $pos);
456 'name' => substr($line, 0, $pos),
457 'type' => $this->types[substr($line, 11, 1)],
458 'length' => ord(substr($line, 16, 1)),
459 'precision' => ord(substr($line, 17, 1)),
468 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
469 $case_func = 'strtolower';
471 $case_func = 'strval';
478 $res['num_fields'] = $count;
481 for ($i = 0; $i < $count; $i++) {
483 'table' => $this->dsn['database'],
484 'name' => $case_func($id[$i]['name']),
485 'type' => $id[$i]['type'],
486 'len' => $id[$i]['length'],
489 if ($mode & DB_TABLEINFO_ORDER) {
490 $res['order'][$res[$i]['name']] = $i;
492 if ($mode & DB_TABLEINFO_ORDERTABLE) {
493 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;