/* +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Jim Winstead | +----------------------------------------------------------------------+ */ /* $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "fopen_wrappers.h" #include "php_globals.h" #include "ext/standard/php_math.h" #ifdef HAVE_SYS_FILE_H # include #endif #include "ext/standard/flock_compat.h" #include #ifdef HAVE_SYS_TYPES_H #include #endif #if DBASE #include "php_dbase.h" #include "dbf.h" static int le_dbhead; #include #include /* compatitibility with PHP 8 */ #ifdef RETURN_THROWS # define RETURN_THROWS_FALSE() RETURN_THROWS() # define RETURN_THROWS_NULL() RETURN_THROWS() #else # define RETURN_THROWS_FALSE() RETURN_FALSE # define RETURN_THROWS_NULL() return #endif #if PHP_VERSION_ID >= 80000 # define BAD_REC_NUMBER(i,n) zend_argument_value_error(i, "record number has to be in range 1..2147483647, but is " ZEND_LONG_FMT, n) #else # define BAD_REC_NUMBER(i,n) php_error_docref(NULL, E_WARNING, "record number has to be in range 1..2147483647, but is " ZEND_LONG_FMT, n) #endif #if PHP_VERSION_ID >= 80000 # include "dbase_arginfo.h" #else # include "dbase_7_arginfo.h" #endif static void _close_dbase(zend_resource *rsrc) { dbhead_t *dbhead = (dbhead_t *)rsrc->ptr; php_flock(dbhead->db_fd, LOCK_UN); close(dbhead->db_fd); free_dbf_head(dbhead); } PHP_MINIT_FUNCTION(dbase) { le_dbhead = zend_register_list_destructors_ex(_close_dbase, NULL, "dbase", module_number); REGISTER_STRING_CONSTANT("DBASE_VERSION", PHP_DBASE_VERSION, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("DBASE_TYPE_DBASE", DBH_TYPE_NORMAL, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("DBASE_TYPE_FOXPRO", DBH_TYPE_FOXPRO, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("DBASE_RDONLY", O_RDONLY, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("DBASE_RDWR", O_RDWR, CONST_CS | CONST_PERSISTENT); return SUCCESS; } /* {{{ proto resource dbase_open(string name, int mode) Opens a dBase-format database file */ PHP_FUNCTION(dbase_open) { zend_string *dbf_name; zend_long mode; dbhead_t *dbh; if (zend_parse_parameters(ZEND_NUM_ARGS(), "Pl", &dbf_name, &mode) == FAILURE) { RETURN_THROWS_NULL(); } if (!ZSTR_LEN(dbf_name)) { php_error_docref(NULL, E_WARNING, "The filename cannot be empty."); RETURN_FALSE; } if (mode == O_WRONLY) { php_error_docref(NULL, E_WARNING, "Cannot open %s in write-only mode", ZSTR_VAL(dbf_name)); RETURN_FALSE; } else if (mode != O_RDONLY && mode != O_RDWR) { php_error_docref(NULL, E_WARNING, "Invalid access mode %ld", mode); RETURN_FALSE; } if (php_check_open_basedir(ZSTR_VAL(dbf_name))) { RETURN_FALSE; } dbh = dbf_open(ZSTR_VAL(dbf_name), (int) mode); if (dbh == NULL) { php_error_docref(NULL, E_WARNING, "unable to open database %s", ZSTR_VAL(dbf_name)); RETURN_FALSE; } RETURN_RES(zend_register_resource(dbh, le_dbhead)); } /* }}} */ /* {{{ proto bool dbase_close(resource identifier) Closes an open dBase-format database file */ PHP_FUNCTION(dbase_close) { zval *dbh_id; if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dbh_id) == FAILURE) { RETURN_THROWS_NULL(); } if (zend_fetch_resource(Z_RES_P(dbh_id), "dbase", le_dbhead) == NULL) { RETURN_THROWS_FALSE(); } zend_list_close(Z_RES_P(dbh_id)); RETURN_TRUE; } /* }}} */ /* {{{ proto int dbase_numrecords(resource identifier) Returns the number of records in the database */ PHP_FUNCTION(dbase_numrecords) { zval *dbh_id; dbhead_t *dbht; if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dbh_id) == FAILURE) { RETURN_THROWS_NULL(); } if ((dbht = (dbhead_t *) zend_fetch_resource(Z_RES_P(dbh_id), "dbase", le_dbhead)) == NULL) { RETURN_THROWS_FALSE(); } RETURN_LONG(dbht->db_records); } /* }}} */ /* {{{ proto int dbase_numfields(resource identifier) Returns the number of fields (columns) in the database */ PHP_FUNCTION(dbase_numfields) { zval *dbh_id; dbhead_t *dbht; if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dbh_id) == FAILURE) { RETURN_THROWS_NULL(); } if ((dbht = (dbhead_t *) zend_fetch_resource(Z_RES_P(dbh_id), "dbase", le_dbhead)) == NULL) { RETURN_THROWS_FALSE(); } RETURN_LONG(dbht->db_nfields - (dbht->db_nnullable ? 1 : 0)); } /* }}} */ /* {{{ proto bool dbase_pack(resource identifier) Packs the database (deletes records marked for deletion) */ PHP_FUNCTION(dbase_pack) { zval *dbh_id; dbhead_t *dbht; if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dbh_id) == FAILURE) { RETURN_THROWS_NULL(); } if ((dbht = (dbhead_t *) zend_fetch_resource(Z_RES_P(dbh_id), "dbase", le_dbhead)) == NULL) { RETURN_THROWS_FALSE(); } if (!pack_dbf(dbht)) { if (put_dbf_info(dbht) != 1) { RETURN_FALSE; } if (put_dbf_eof_marker(dbht)) { RETURN_FALSE; } RETURN_TRUE; } RETURN_FALSE; } /* }}} */ /* {{{ php_dbase_put_record */ static void php_dbase_put_record(INTERNAL_FUNCTION_PARAMETERS, int replace) { HashTable *fields; zval *field; zend_long recnum; zval *dbh_id; dbhead_t *dbht; int num_fields; dbfield_t *dbf, *cur_f; char *cp, *t_cp; int i; char nullable_flags[DBH_MAX_FIELDS / 8]; if (replace) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "rhl", &dbh_id, &fields, &recnum) == FAILURE) { RETURN_THROWS_NULL(); } if (recnum < 1 || recnum > 0x7FFFFFFF) { BAD_REC_NUMBER(3, recnum); RETURN_THROWS_FALSE(); } } else { if (zend_parse_parameters(ZEND_NUM_ARGS(), "rh", &dbh_id, &fields) == FAILURE) { RETURN_THROWS_NULL(); } } if ((dbht = (dbhead_t *) zend_fetch_resource(Z_RES_P(dbh_id), "dbase", le_dbhead)) == NULL) { RETURN_THROWS_FALSE(); } memset(nullable_flags, 0, sizeof(nullable_flags)); num_fields = zend_hash_num_elements(fields); if (num_fields != dbht->db_nfields - (dbht->db_nnullable ? 1 : 0)) { php_error_docref(NULL, E_WARNING, "expected %d fields, but got %d", dbht->db_nfields, num_fields); RETURN_FALSE; } cp = t_cp = (char *)emalloc(dbht->db_rlen + 1); *t_cp++ = VALID_RECORD; dbf = dbht->db_fields; for (i = 0, cur_f = dbf; cur_f < &dbf[num_fields]; i++, cur_f++) { zend_string *field_val; if ((field = zend_hash_index_find(fields, i)) == NULL) { php_error_docref(NULL, E_WARNING, "expected plain indexed array"); efree(cp); RETURN_FALSE; } if (Z_TYPE_P(field) == IS_NULL && cur_f->db_fnullable >= 0) { nullable_flags[cur_f->db_fnullable / 8] |= (1 << (cur_f->db_fnullable % 8)); } if (Z_TYPE_P(field) == IS_DOUBLE && (cur_f->db_type == 'N' || cur_f->db_type == 'F')) { /* convert to string as if in C locale */ field_val = _php_math_number_format_ex(Z_DVAL_P(field), cur_f->db_fdc, ".", 1, "", 0); } else { field_val = zval_get_string(field); if (EG(exception)) { zend_string_release(field_val); efree(cp); RETURN_FALSE; } } switch (cur_f->db_type) { case 'T': { int jdn, msecs; db_get_timestamp(ZSTR_VAL(field_val), &jdn, &msecs); put_long(t_cp, jdn); put_long(t_cp + 4, msecs); } break; default: snprintf(t_cp, cur_f->db_flen+1, cur_f->db_format, ZSTR_VAL(field_val)); } zend_string_release(field_val); t_cp += cur_f->db_flen; } if (dbht->db_nnullable > 0) { memcpy(t_cp, nullable_flags, (dbht->db_nnullable - 1) / 8 + 1); } if (!replace) { dbht->db_records++; } if (put_dbf_record(dbht, (replace ? (long) recnum : dbht->db_records), cp) < 0) { php_error_docref(NULL, E_WARNING, "unable to put record at %ld", dbht->db_records); efree(cp); RETURN_FALSE; } efree(cp); if (put_dbf_info(dbht) != 1) { RETURN_FALSE; } if (put_dbf_eof_marker(dbht)) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ proto bool dbase_add_record(resource identifier, array data) Adds a record to the database */ PHP_FUNCTION(dbase_add_record) { php_dbase_put_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ proto bool dbase_replace_record(resource identifier, array data, int recnum) Replaces a record to the database */ PHP_FUNCTION(dbase_replace_record) { php_dbase_put_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ /* {{{ proto bool dbase_delete_record(resource identifier, int record) Marks a record to be deleted */ PHP_FUNCTION(dbase_delete_record) { zend_long record; zval *dbh_id; dbhead_t *dbht; if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &dbh_id, &record) == FAILURE) { RETURN_THROWS_NULL(); } if ((dbht = (dbhead_t *) zend_fetch_resource(Z_RES_P(dbh_id), "dbase", le_dbhead)) == NULL) { RETURN_THROWS_FALSE(); } if (record < 1 || record > 0x7FFFFFFF) { BAD_REC_NUMBER(2, record); RETURN_THROWS_FALSE(); } if (del_dbf_record(dbht, (long) record) < 0) { if (record > dbht->db_records) { php_error_docref(NULL, E_WARNING, "record %ld out of bounds", record); } else { php_error_docref(NULL, E_WARNING, "unable to delete record %ld", record); } RETURN_FALSE; } if (put_dbf_info(dbht) != 1) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ php_dbase_get_record */ static void php_dbase_get_record(INTERNAL_FUNCTION_PARAMETERS, int assoc) { zend_long record; dbhead_t *dbht; zval *dbh_id; dbfield_t *dbf, *cur_f; char *data, *fnp, *str_value; size_t cursize = 0; zend_long overflow_test; int errno_save; char nullable_flags[DBH_MAX_FIELDS / 8]; if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &dbh_id, &record) == FAILURE) { RETURN_THROWS_NULL(); } if ((dbht = (dbhead_t *) zend_fetch_resource(Z_RES_P(dbh_id), "dbase", le_dbhead)) == NULL) { RETURN_THROWS_FALSE(); } if (record < 1 || record > 0x7FFFFFFF) { BAD_REC_NUMBER(2, record); RETURN_THROWS_FALSE(); } if ((data = get_dbf_record(dbht, (long) record)) == NULL) { php_error_docref(NULL, E_WARNING, "Tried to read bad record %ld", record); RETURN_FALSE; } dbf = dbht->db_fields; if (dbht->db_nnullable > 0) { memset(nullable_flags, 0, sizeof(nullable_flags)); cur_f = &dbf[dbht->db_nfields - 1]; get_binary_field_val(data, cur_f, nullable_flags); } array_init(return_value); fnp = NULL; for (cur_f = dbf; cur_f < &dbf[dbht->db_nfields - (dbht->db_nnullable ? 1 : 0)]; cur_f++) { if (cur_f->db_fnullable >= 0 && (nullable_flags[cur_f->db_fnullable / 8] & (1 << (cur_f->db_fnullable % 8)))) { if (!assoc) { add_next_index_null(return_value); } else { add_assoc_null(return_value, cur_f->db_fname); } continue; } /* get the value */ str_value = (char *)emalloc(cur_f->db_flen + 1); if(cursize <= (unsigned)cur_f->db_flen) { cursize = cur_f->db_flen + 1; fnp = erealloc(fnp, cursize); } if (*cur_f->db_format) { snprintf(str_value, cursize, cur_f->db_format, get_field_val(data, cur_f, fnp)); } else { memcpy(str_value, get_binary_field_val(data, cur_f, fnp), cur_f->db_flen); } /* now convert it to the right php internal type */ switch (cur_f->db_type) { case 'C': case 'D': if (!assoc) { add_next_index_string(return_value, str_value); } else { add_assoc_string(return_value, cur_f->db_fname, str_value); } break; case 'N': if (cur_f->db_fdc == 0) { /* Large integers in dbase can be larger than long */ errno_save = errno; overflow_test = ZEND_STRTOL(str_value, NULL, 10); if (errno == ERANGE) { /* If the integer is too large, keep it as string */ if (!assoc) { add_next_index_string(return_value, str_value); } else { add_assoc_string(return_value, cur_f->db_fname, str_value); } } else { if (!assoc) { add_next_index_long(return_value, overflow_test); } else { add_assoc_long(return_value, cur_f->db_fname, overflow_test); } } errno = errno_save; } else { if (!assoc) { add_next_index_double(return_value, zend_strtod(str_value, NULL)); } else { add_assoc_double(return_value, cur_f->db_fname, zend_strtod(str_value, NULL)); } } break; case 'F': if (!assoc) { add_next_index_double(return_value, zend_strtod(str_value, NULL)); } else { add_assoc_double(return_value, cur_f->db_fname, zend_strtod(str_value, NULL)); } break; case 'L': /* we used to FALL THROUGH, but now we check for T/Y and F/N and insert 1 or 0, respectively. db_fdc is the number of decimals, which we don't care about. 3/14/2001 LEW */ if ((*str_value == 'T') || (*str_value == 'Y')) { if (!assoc) { add_next_index_bool(return_value, 1); } else { add_assoc_bool(return_value, cur_f->db_fname, 1); } } else if (*str_value == '?') { if (!assoc) { add_next_index_null(return_value); } else { add_assoc_null(return_value, cur_f->db_fname); } } else { if (!assoc) { add_next_index_bool(return_value, 0); } else { add_assoc_bool(return_value, cur_f->db_fname, 0); } } break; case 'M': /* this is a memo field. don't know how to deal with this yet */ break; case 'T': { char buf[19]; db_set_timestamp(buf, get_long(str_value), get_long(str_value + 4)); if (!assoc) { add_next_index_string(return_value, buf); } else { add_assoc_string(return_value, cur_f->db_fname, buf); } } break; default: /* should deal with this in some way */ break; } efree(str_value); } efree(fnp); /* mark whether this record was deleted */ if (data[0] == '*') { add_assoc_long(return_value, "deleted", 1); } else { add_assoc_long(return_value, "deleted", 0); } efree(data); } /* }}} */ /* {{{ proto array dbase_get_record(resource identifier, int record) Returns an array representing a record from the database */ PHP_FUNCTION(dbase_get_record) { php_dbase_get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* From Martin Kuba */ /* {{{ proto array dbase_get_record_with_names(resource identifier, int record) Returns an associative array representing a record from the database */ PHP_FUNCTION(dbase_get_record_with_names) { php_dbase_get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ static dbhead_t *create_head_from_spec(HashTable *fields, int fd, unsigned char type) { int num_fields; dbfield_t *dbf, *cur_f; int i, rlen; zval *field, *value; dbhead_t *dbh; int nullable_bit = 0; num_fields = zend_hash_num_elements(fields); if (num_fields <= 0) { php_error_docref(NULL, E_WARNING, "Unable to create database without fields"); return NULL; } dbh = (dbhead_t *)emalloc(sizeof(dbhead_t)); dbf = (dbfield_t *)emalloc(sizeof(dbfield_t) * (num_fields + 1)); /* initialize the header structure */ dbh->db_fields = dbf; dbh->db_fd = fd; dbh->db_dbt = type; strcpy(dbh->db_date, "19930818"); dbh->db_records = 0; dbh->db_nfields = num_fields; dbh->db_hlen = sizeof(struct dbf_dhead) + 1 + num_fields * sizeof(struct dbf_dfield); if (type == DBH_TYPE_FOXPRO) { dbh->db_hlen += 263; } rlen = 1; /** * Patch by greg@darkphoton.com **/ /* make sure that the db_format entries for all fields are set to NULL to ensure we don't seg fault if there's an error and we need to call free_dbf_head() before all fields have been defined. */ for (i = 0, cur_f = dbf; i < num_fields + 1; i++, cur_f++) { cur_f->db_format = NULL; } /** * end patch */ for (i = 0, cur_f = dbf; i < num_fields; i++, cur_f++) { int element = 0; zval tmp_value; /* look up the field */ if ((field = zend_hash_index_find(fields, i)) == NULL) { php_error_docref(NULL, E_WARNING, "expected plain indexed array"); goto fail; } /* field name */ if (Z_TYPE_P(field) != IS_ARRAY || (value = zend_hash_index_find(Z_ARRVAL_P(field), element)) == NULL) { php_error_docref(NULL, E_WARNING, "expected field name as element %d of list in field %d", element, i); goto fail; } ZVAL_COPY_VALUE(&tmp_value, value); zval_copy_ctor(&tmp_value); convert_to_string(&tmp_value); if (EG(exception)) { zval_dtor(&tmp_value); goto fail; } if (Z_STRLEN(tmp_value) > 10 || Z_STRLEN(tmp_value) == 0) { php_error_docref(NULL, E_WARNING, "invalid field name '%s' (must be non-empty and less than or equal to 10 characters)", Z_STRVAL(tmp_value)); zval_dtor(&tmp_value); goto fail; } copy_crimp(cur_f->db_fname, Z_STRVAL(tmp_value), (int) Z_STRLEN(tmp_value)); zval_dtor(&tmp_value); /* field type */ if ((value = zend_hash_index_find(Z_ARRVAL_P(field), ++element)) == NULL) { php_error_docref(NULL, E_WARNING, "expected field type as element %d of list in field %d", element, i); goto fail; } ZVAL_COPY_VALUE(&tmp_value, value); zval_copy_ctor(&tmp_value); convert_to_string(&tmp_value); if (EG(exception)) { zval_dtor(&tmp_value); goto fail; } cur_f->db_type = toupper(*Z_STRVAL(tmp_value)); zval_dtor(&tmp_value); cur_f->db_fdc = 0; /* verify the field length */ switch (cur_f->db_type) { case 'L': cur_f->db_flen = 1; break; case 'M': cur_f->db_flen = 10; dbh->db_dbt = DBH_TYPE_MEMO; /* should create the memo file here, probably */ break; case 'D': cur_f->db_flen = 8; break; case 'T': if (type != DBH_TYPE_FOXPRO) { php_error_docref(NULL, E_WARNING, "datetime fields are not supported by dBASE"); goto fail; } cur_f->db_flen = 8; break; case 'F': case 'N': case 'C': /* field length */ if ((value = zend_hash_index_find(Z_ARRVAL_P(field), ++element)) == NULL) { php_error_docref(NULL, E_WARNING, "expected field length as element %d of list in field %d", element, i); goto fail; } ZVAL_COPY_VALUE(&tmp_value, value); zval_copy_ctor(&tmp_value); convert_to_long(&tmp_value); if (Z_LVAL(tmp_value) < 0 || Z_LVAL(tmp_value) > 254) { php_error_docref(NULL, E_WARNING, "expected length of field %d to be in range 0..254, but got " ZEND_LONG_FMT, i, Z_LVAL(tmp_value)); zval_dtor(&tmp_value); goto fail; } cur_f->db_flen = (unsigned char) Z_LVAL(tmp_value); zval_dtor(&tmp_value); if (cur_f->db_type == 'N' || cur_f->db_type == 'F') { if ((value = zend_hash_index_find(Z_ARRVAL_P(field), ++element)) == NULL) { php_error_docref(NULL, E_WARNING, "expected field precision as element %d of list in field %d", element, i); goto fail; } ZVAL_COPY_VALUE(&tmp_value, value); zval_copy_ctor(&tmp_value); convert_to_long(&tmp_value); if (Z_LVAL(tmp_value) < 0 || Z_LVAL(tmp_value) > 254) { php_error_docref(NULL, E_WARNING, "expected precision of field %d to be in range 0..254, but got " ZEND_LONG_FMT, i, Z_LVAL(tmp_value)); zval_dtor(&tmp_value); goto fail; } cur_f->db_fdc = (unsigned char) Z_LVAL(tmp_value); zval_dtor(&tmp_value); } break; default: php_error_docref(NULL, E_WARNING, "unknown field type '%c'", cur_f->db_type); goto fail; } cur_f->db_foffset = rlen; rlen += cur_f->db_flen; cur_f->db_format = get_dbf_f_fmt(cur_f); cur_f->db_fnullable = -1; if (type == DBH_TYPE_FOXPRO && (value = zend_hash_index_find(Z_ARRVAL_P(field), ++element)) != NULL) { ZVAL_COPY_VALUE(&tmp_value, value); zval_copy_ctor(&tmp_value); convert_to_boolean(&tmp_value); if (Z_TYPE(tmp_value) == IS_TRUE) { cur_f->db_fnullable = nullable_bit++; } zval_dtor(&tmp_value); } } if (nullable_bit) { dbh->db_nfields++; dbh->db_hlen += sizeof(struct dbf_dfield); copy_crimp(cur_f->db_fname, "_NullFlags", sizeof("_NullFlags") - 1); cur_f->db_type = '0'; cur_f->db_flen = ((nullable_bit - 1)) / 8 + 1; cur_f->db_fdc = 0; cur_f->db_format = estrdup(""); cur_f->db_foffset = rlen; cur_f->db_fnullable = -1; rlen += cur_f->db_flen; } dbh->db_nnullable = nullable_bit; dbh->db_rlen = rlen; return dbh; fail: free_dbf_head(dbh); return NULL; } /* {{{ proto resource dbase_create(string filename, array fields [, int type]) Creates a new dBase-format database file */ PHP_FUNCTION(dbase_create) { zend_string *filename; HashTable *fields; zend_long type = DBH_TYPE_NORMAL; int fd; dbhead_t *dbh; if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ph|l", &filename, &fields, &type) == FAILURE) { RETURN_THROWS_NULL(); } if (php_check_open_basedir(ZSTR_VAL(filename))) { RETURN_FALSE; } if ((fd = VCWD_OPEN_MODE(ZSTR_VAL(filename), O_BINARY|O_RDWR|O_CREAT, 0644)) < 0) { php_error_docref(NULL, E_WARNING, "Unable to create database (%d): %s", errno, strerror(errno)); RETURN_FALSE; } if (php_flock(fd, LOCK_EX)) { php_error_docref(NULL, E_WARNING, "unable to lock database"); goto fail; } if (type != DBH_TYPE_NORMAL && type != DBH_TYPE_FOXPRO) { php_error_docref(NULL, E_WARNING, "unknown database type " ZEND_LONG_FMT, type); goto fail; } if ((dbh = create_head_from_spec(fields, fd, (unsigned char) type)) == NULL) { goto fail; } if (put_dbf_info(dbh) != 1 || put_dbf_eof_marker(dbh)) { free_dbf_head(dbh); goto fail; } RETURN_RES(zend_register_resource(dbh, le_dbhead)); fail: close(fd); RETURN_FALSE; } /* }}} */ /* Added by Zak Greant */ /* {{{ proto array dbase_get_header_info(resource database_handle) */ PHP_FUNCTION(dbase_get_header_info) { zval row; dbhead_t *dbht; zval *dbh_id; dbfield_t *dbf, *cur_f; if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dbh_id) == FAILURE) { RETURN_THROWS_NULL(); } if ((dbht = (dbhead_t *) zend_fetch_resource(Z_RES_P(dbh_id), "dbase", le_dbhead)) == NULL) { RETURN_THROWS_FALSE(); } array_init(return_value); dbf = dbht->db_fields; for (cur_f = dbf; cur_f < &dbht->db_fields[dbht->db_nfields]; ++cur_f) { if (cur_f->db_type == '0') { continue; } array_init(&row); add_next_index_zval(return_value, &row); /* field name */ add_assoc_string(&row, "name", cur_f->db_fname); /* field type */ switch (cur_f->db_type) { case 'C': add_assoc_string(&row, "type", "character"); break; case 'D': add_assoc_string(&row, "type", "date"); break; case 'T': add_assoc_string(&row, "type", "datetime"); break; case 'N': add_assoc_string(&row, "type", "number"); break; case 'L': add_assoc_string(&row, "type", "boolean"); break; case 'M': add_assoc_string(&row, "type", "memo"); break; case 'F': add_assoc_string(&row, "type", "float"); break; default: add_assoc_string(&row, "type", "unknown"); break; } /* length of field */ add_assoc_long(&row, "length", cur_f->db_flen); /* number of decimals in field */ switch (cur_f->db_type) { case 'F': case 'N': add_assoc_long(&row, "precision", cur_f->db_fdc); break; default: add_assoc_long(&row, "precision", 0); } /* format for printing %s etc */ add_assoc_string(&row, "format", cur_f->db_format); /* offset within record */ add_assoc_long(&row, "offset", cur_f->db_foffset); } } /* }}} */ zend_module_entry dbase_module_entry = { STANDARD_MODULE_HEADER, "dbase", ext_functions, PHP_MINIT(dbase), NULL, NULL, NULL, NULL, PHP_DBASE_VERSION, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_DBASE ZEND_GET_MODULE(dbase) #if defined(PHP_WIN32) && defined(THREAD_SAFE) /*NOTE: You should have an odbc.def file where you export DllMain*/ BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return 1; } #endif #endif #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */