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
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';
31 require_once 'common.php';
34 * The methods PEAR DB uses to interact with PHP's dbase extension
35 * for interacting with dBase databases
37 * These methods overload the ones declared in DB_common.
41 * @author Tomas V.V. Cox <cox@idecnet.com>
42 * @author Daniel Convissor <danielc@php.net>
43 * @copyright 1997-2007 The PHP Group
44 * @license http://www.php.net/license/3_0.txt PHP License 3.0
45 * @version Release: 1.9.2
46 * @link http://pear.php.net/package/DB
48 class DB_dbase extends DB_common
53 * The DB driver type (mysql, oci8, odbc, etc.)
56 public $phptype = 'dbase';
59 * The database syntax variant to be used (db2, access, etc.), if any
62 public $dbsyntax = 'dbase';
65 * The capabilities of this DB implementation
67 * The 'new_link' element contains the PHP version that first provided
68 * new_link support for this DBMS. Contains false if it's unsupported.
70 * Meaning of the 'limit' element:
71 * + 'emulate' = emulate with fetch row by number
72 * + 'alter' = alter the query
77 public $features = array(
84 'transactions' => false,
88 * A mapping of native error codes to DB error codes
91 public $errorcode_map = array();
94 * The raw database connection created by PHP
100 * The DSN information for connecting to a database
103 public $dsn = array();
107 * A means of emulating result resources
110 public $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
130 public $types = array(
143 * This constructor calls <kbd>parent::__construct()</kbd>
147 public function __construct()
149 parent::__construct();
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 ((new PEAR)->isError($db)) {
193 * die($db->getMessage());
197 * @param array $dsn the data source name
198 * @param bool $persistent should the connection be persistent?
202 public 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(
224 DB_ERROR_CONNECT_FAILED,
228 'the dbase file does not exist and '
229 . 'it could not be created because '
230 . 'the "fields" element of the DSN '
231 . 'is not properly set'
234 $this->connection = @dbase_create(
238 if (!$this->connection) {
239 return $this->raiseError(
240 DB_ERROR_CONNECT_FAILED,
244 'the dbase file does not exist and '
245 . 'the attempt to create it failed: '
250 if (!isset($this->dsn['mode'])) {
251 $this->dsn['mode'] = 0;
253 $this->connection = @dbase_open(
257 if (!$this->connection) {
258 return $this->raiseError(
259 DB_ERROR_CONNECT_FAILED,
274 * Disconnects from the database server
276 * @return bool TRUE on success, FALSE on failure
278 public function disconnect()
280 $ret = @dbase_close($this->connection);
281 $this->connection = null;
288 public function &query($query = null)
290 // emulate result resources
291 $this->res_row[(int)$this->result] = 0;
292 $tmp = new DB_result($this, $this->result++);
300 * Places a row from the result set into the given array
302 * Formating of the array and the data therein are configurable.
303 * See DB_result::fetchInto() for more information.
305 * This method is not meant to be called directly. Use
306 * DB_result::fetchInto() instead. It can't be declared "protected"
307 * because DB_result is a separate object.
309 * @param resource $result the query result resource
310 * @param array $arr the referenced array to put the data in
311 * @param int $fetchmode how the resulting array should be indexed
312 * @param int $rownum the row number to fetch (0 = first row)
314 * @return mixed DB_OK on success, NULL when the end of a result set is
315 * reached or on failure
317 * @see DB_result::fetchInto()
319 public function fetchInto($result, &$arr, $fetchmode, $rownum = null)
321 if ($rownum === null) {
322 $rownum = $this->res_row[(int)$result]++;
324 if ($fetchmode & DB_FETCHMODE_ASSOC) {
325 $arr = @dbase_get_record_with_names($this->connection, $rownum);
326 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
327 $arr = array_change_key_case($arr, CASE_LOWER);
330 $arr = @dbase_get_record($this->connection, $rownum);
335 if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
336 $this->_rtrimArrayValues($arr);
338 if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
339 $this->_convertNullArrayValuesToEmpty($arr);
348 * Deletes the result set and frees the memory occupied by the result set.
350 * This method is a no-op for dbase, as there aren't result resources in
351 * the same sense as most other database backends.
353 * @param resource $result PHP's query result resource
355 * @return bool TRUE on success, FALSE if $result is invalid
357 * @see DB_result::free()
359 public function freeResult($result)
368 * Gets the number of columns in a result set
370 * This method is not meant to be called directly. Use
371 * DB_result::numCols() instead. It can't be declared "protected"
372 * because DB_result is a separate object.
375 * @return int the number of columns. A DB_Error object on failure.
377 * @see DB_result::numCols()
379 public function numCols($foo)
381 return @dbase_numfields($this->connection);
388 * Gets the number of rows in a result set
390 * This method is not meant to be called directly. Use
391 * DB_result::numRows() instead. It can't be declared "protected"
392 * because DB_result is a separate object.
395 * @return int the number of rows. A DB_Error object on failure.
397 * @see DB_result::numRows()
399 public function numRows($foo)
401 return @dbase_numrecords($this->connection);
405 // {{{ quoteBoolean()
408 * Formats a boolean value for use within a query in a locale-independent
411 * @param boolean the boolean value to be quoted.
412 * @return string the quoted string.
413 * @see DB_common::quoteSmart()
414 * @since Method available since release 1.7.8.
416 public function quoteBoolean($boolean)
418 return $boolean ? 'T' : 'F';
425 * Returns information about the current database
427 * @param mixed $result THIS IS UNUSED IN DBASE. The current database
428 * is examined regardless of what is provided here.
429 * @param int $mode a valid tableInfo mode
431 * @return array|object
432 * A DB_Error object on failure.
434 * @see DB_common::tableInfo()
435 * @since Method available since Release 1.7.0
437 public function tableInfo($result = null, $mode = null)
439 if (function_exists('dbase_get_header_info')) {
440 $id = @dbase_get_header_info($this->connection);
441 if (!$id && $php_errormsg) {
442 return $this->raiseError(
452 * This segment for PHP 4 is loosely based on code by
453 * Hadi Rusiah <deegos@yahoo.com> in the comments on
454 * the dBase reference page in the PHP manual.
456 $db = @fopen($this->dsn['database'], 'r');
458 return $this->raiseError(
459 DB_ERROR_CONNECT_FAILED,
470 $line = fread($db, 32);
472 $line = fread($db, 32);
473 if (substr($line, 0, 1) == chr(13)) {
476 $pos = strpos(substr($line, 0, 10), chr(0));
477 $pos = ($pos == 0 ? 10 : $pos);
479 'name' => substr($line, 0, $pos),
480 'type' => $this->types[substr($line, 11, 1)],
481 'length' => ord(substr($line, 16, 1)),
482 'precision' => ord(substr($line, 17, 1)),
491 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
492 $case_func = 'strtolower';
494 $case_func = 'strval';
501 $res['num_fields'] = $count;
504 for ($i = 0; $i < $count; $i++) {
506 'table' => $this->dsn['database'],
507 'name' => $case_func($id[$i]['name']),
508 'type' => $id[$i]['type'],
509 'len' => $id[$i]['length'],
512 if ($mode & DB_TABLEINFO_ORDER) {
513 $res['order'][$res[$i]['name']] = $i;
515 if ($mode & DB_TABLEINFO_ORDERTABLE) {
516 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;