1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: Jim Winstead <jimw@php.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: dbase.c 272374 2008-12-31 11:17:49Z sebastian $ */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 : #include "safe_mode.h"
27 : #include "fopen_wrappers.h"
28 : #include "php_globals.h"
29 :
30 : #include <stdlib.h>
31 :
32 : #ifdef HAVE_SYS_TYPES_H
33 : #include <sys/types.h>
34 : #endif
35 :
36 : #if DBASE
37 : #include "php_dbase.h"
38 : #include "dbf.h"
39 : #if defined(THREAD_SAFE)
40 : DWORD DbaseTls;
41 : static int numthreads=0;
42 : void *dbase_mutex;
43 :
44 : typedef struct dbase_global_struct{
45 : int le_dbhead;
46 : }dbase_global_struct;
47 :
48 : #define DBase_GLOBAL(a) dbase_globals->a
49 :
50 : #define DBase_TLS_VARS \
51 : dbase_global_struct *dbase_globals; \
52 : dbase_globals=TlsGetValue(DbaseTls);
53 :
54 : #else
55 : static int le_dbhead;
56 : #define DBase_GLOBAL(a) a
57 : #define DBase_TLS_VARS
58 : #endif
59 :
60 : #include <fcntl.h>
61 : #include <errno.h>
62 :
63 :
64 : static void _close_dbase(zend_rsrc_list_entry *rsrc TSRMLS_DC)
65 13 : {
66 13 : dbhead_t *dbhead = (dbhead_t *)rsrc->ptr;
67 :
68 13 : close(dbhead->db_fd);
69 13 : free_dbf_head(dbhead);
70 13 : }
71 :
72 :
73 : PHP_MINIT_FUNCTION(dbase)
74 13565 : {
75 : #if defined(THREAD_SAFE)
76 : dbase_global_struct *dbase_globals;
77 : #ifdef COMPILE_DL_DBASE
78 : CREATE_MUTEX(dbase_mutex, "DBase_TLS");
79 : SET_MUTEX(dbase_mutex);
80 : numthreads++;
81 : if (numthreads==1){
82 : if ((DbaseTls=TlsAlloc())==0xFFFFFFFF){
83 : FREE_MUTEX(dbase_mutex);
84 : return 0;
85 : }}
86 : FREE_MUTEX(dbase_mutex);
87 : #endif
88 : dbase_globals = (dbase_global_struct *) LocalAlloc(LPTR, sizeof(dbase_global_struct));
89 : TlsSetValue(DbaseTls, (void *) dbase_globals);
90 : #endif
91 13565 : DBase_GLOBAL(le_dbhead) =
92 : zend_register_list_destructors_ex(_close_dbase, NULL, "dbase", module_number);
93 13565 : return SUCCESS;
94 : }
95 :
96 : static PHP_MSHUTDOWN_FUNCTION(dbase)
97 13597 : {
98 : #if defined(THREAD_SAFE)
99 : dbase_global_struct *dbase_globals;
100 : dbase_globals = TlsGetValue(DbaseTls);
101 : if (dbase_globals != 0)
102 : LocalFree((HLOCAL) dbase_globals);
103 : #ifdef COMPILE_DL_DBASE
104 : SET_MUTEX(dbase_mutex);
105 : numthreads--;
106 : if (!numthreads){
107 : if (!TlsFree(DbaseTls)){
108 : FREE_MUTEX(dbase_mutex);
109 : return 0;
110 : }}
111 : FREE_MUTEX(dbase_mutex);
112 : #endif
113 : #endif
114 13597 : return SUCCESS;
115 : }
116 :
117 : /* {{{ proto int dbase_open(string name, int mode)
118 : Opens a dBase-format database file */
119 : PHP_FUNCTION(dbase_open)
120 11 : {
121 : zval **dbf_name, **options;
122 : dbhead_t *dbh;
123 : int handle;
124 : DBase_TLS_VARS;
125 :
126 11 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &dbf_name, &options) == FAILURE) {
127 0 : WRONG_PARAM_COUNT;
128 : }
129 11 : convert_to_string_ex(dbf_name);
130 11 : convert_to_long_ex(options);
131 :
132 11 : if (!Z_STRLEN_PP(dbf_name)) {
133 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The filename cannot be empty.");
134 1 : RETURN_FALSE;
135 : }
136 :
137 10 : if (Z_LVAL_PP(options) == 1) {
138 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot open %s in write-only mode", Z_STRVAL_PP(dbf_name));
139 1 : RETURN_FALSE;
140 9 : } else if (Z_LVAL_PP(options) < 0 || Z_LVAL_PP(options) > 3) {
141 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid access mode %ld", Z_LVAL_PP(options));
142 2 : RETURN_FALSE;
143 : }
144 :
145 7 : if (PG(safe_mode) && (!php_checkuid(Z_STRVAL_PP(dbf_name), NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
146 0 : RETURN_FALSE;
147 : }
148 :
149 7 : if (php_check_open_basedir(Z_STRVAL_PP(dbf_name) TSRMLS_CC)) {
150 0 : RETURN_FALSE;
151 : }
152 :
153 7 : dbh = dbf_open(Z_STRVAL_PP(dbf_name), Z_LVAL_PP(options) TSRMLS_CC);
154 7 : if (dbh == NULL) {
155 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to open database %s", Z_STRVAL_PP(dbf_name));
156 2 : RETURN_FALSE;
157 : }
158 :
159 5 : handle = zend_list_insert(dbh, DBase_GLOBAL(le_dbhead));
160 5 : RETURN_LONG(handle);
161 : }
162 : /* }}} */
163 :
164 : /* {{{ proto bool dbase_close(int identifier)
165 : Closes an open dBase-format database file */
166 : PHP_FUNCTION(dbase_close)
167 5 : {
168 : zval **dbh_id;
169 : dbhead_t *dbh;
170 : int dbh_type;
171 : DBase_TLS_VARS;
172 :
173 5 : if (ZEND_NUM_ARGS() != 1 || (zend_get_parameters_ex(1, &dbh_id) == FAILURE)) {
174 0 : WRONG_PARAM_COUNT;
175 : }
176 5 : convert_to_long_ex(dbh_id);
177 5 : dbh = zend_list_find(Z_LVAL_PP(dbh_id), &dbh_type);
178 5 : if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
179 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find database for identifier %ld", Z_LVAL_PP(dbh_id));
180 0 : RETURN_FALSE;
181 : }
182 :
183 5 : zend_list_delete(Z_LVAL_PP(dbh_id));
184 5 : RETURN_TRUE;
185 : }
186 : /* }}} */
187 :
188 : /* {{{ proto int dbase_numrecords(int identifier)
189 : Returns the number of records in the database */
190 : PHP_FUNCTION(dbase_numrecords)
191 1 : {
192 : zval **dbh_id;
193 : dbhead_t *dbh;
194 : int dbh_type;
195 : DBase_TLS_VARS;
196 :
197 1 : if (ZEND_NUM_ARGS() != 1 || (zend_get_parameters_ex(1, &dbh_id) == FAILURE)) {
198 0 : WRONG_PARAM_COUNT;
199 : }
200 1 : convert_to_long_ex(dbh_id);
201 1 : dbh = zend_list_find(Z_LVAL_PP(dbh_id), &dbh_type);
202 1 : if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
203 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find database for identifier %ld", Z_LVAL_PP(dbh_id));
204 0 : RETURN_FALSE;
205 : }
206 :
207 1 : RETURN_LONG(dbh->db_records);
208 : }
209 : /* }}} */
210 :
211 : /* {{{ proto int dbase_numfields(int identifier)
212 : Returns the number of fields (columns) in the database */
213 : PHP_FUNCTION(dbase_numfields)
214 1 : {
215 : zval **dbh_id;
216 : dbhead_t *dbh;
217 : int dbh_type;
218 : DBase_TLS_VARS;
219 :
220 1 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &dbh_id) == FAILURE) {
221 0 : WRONG_PARAM_COUNT;
222 : }
223 1 : convert_to_long_ex(dbh_id);
224 1 : dbh = zend_list_find(Z_LVAL_PP(dbh_id), &dbh_type);
225 1 : if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
226 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find database for identifier %ld", Z_LVAL_PP(dbh_id));
227 0 : RETURN_FALSE;
228 : }
229 :
230 1 : RETURN_LONG(dbh->db_nfields);
231 : }
232 : /* }}} */
233 :
234 : /* {{{ proto bool dbase_pack(int identifier)
235 : Packs the database (deletes records marked for deletion) */
236 : PHP_FUNCTION(dbase_pack)
237 1 : {
238 : zval **dbh_id;
239 : dbhead_t *dbh;
240 : int dbh_type;
241 : DBase_TLS_VARS;
242 :
243 1 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &dbh_id) == FAILURE) {
244 0 : WRONG_PARAM_COUNT;
245 : }
246 1 : convert_to_long_ex(dbh_id);
247 1 : dbh = zend_list_find(Z_LVAL_PP(dbh_id), &dbh_type);
248 1 : if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
249 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find database for identifier %ld", Z_LVAL_PP(dbh_id));
250 0 : RETURN_FALSE;
251 : }
252 :
253 1 : pack_dbf(dbh);
254 1 : put_dbf_info(dbh);
255 1 : RETURN_TRUE;
256 : }
257 : /* }}} */
258 :
259 : /* {{{ proto bool dbase_add_record(int identifier, array data)
260 : Adds a record to the database */
261 : PHP_FUNCTION(dbase_add_record)
262 8 : {
263 : zval **dbh_id, **fields, **field;
264 : dbhead_t *dbh;
265 : int dbh_type;
266 :
267 : int num_fields;
268 : dbfield_t *dbf, *cur_f;
269 : char *cp, *t_cp;
270 : int i;
271 : DBase_TLS_VARS;
272 :
273 8 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &dbh_id, &fields) == FAILURE) {
274 0 : WRONG_PARAM_COUNT;
275 : }
276 8 : convert_to_long_ex(dbh_id);
277 8 : if (Z_TYPE_PP(fields) != IS_ARRAY) {
278 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array as second parameter");
279 0 : RETURN_FALSE;
280 : }
281 :
282 8 : dbh = zend_list_find(Z_LVAL_PP(dbh_id), &dbh_type);
283 8 : if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
284 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find database for identifier %ld", Z_LVAL_PP(dbh_id));
285 0 : RETURN_FALSE;
286 : }
287 :
288 8 : num_fields = zend_hash_num_elements(Z_ARRVAL_PP(fields));
289 :
290 8 : if (num_fields != dbh->db_nfields) {
291 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong number of fields specified");
292 0 : RETURN_FALSE;
293 : }
294 :
295 8 : cp = t_cp = (char *)emalloc(dbh->db_rlen + 1);
296 8 : *t_cp++ = VALID_RECORD;
297 :
298 8 : dbf = dbh->db_fields;
299 40 : for (i = 0, cur_f = dbf; cur_f < &dbf[num_fields]; i++, cur_f++) {
300 : zval tmp;
301 32 : if (zend_hash_index_find(Z_ARRVAL_PP(fields), i, (void **)&field) == FAILURE) {
302 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unexpected error");
303 0 : efree(cp);
304 0 : RETURN_FALSE;
305 : }
306 :
307 32 : tmp = **field;
308 32 : zval_copy_ctor(&tmp);
309 32 : convert_to_string(&tmp);
310 32 : snprintf(t_cp, cur_f->db_flen+1, cur_f->db_format, Z_STRVAL(tmp));
311 32 : zval_dtor(&tmp);
312 32 : t_cp += cur_f->db_flen;
313 : }
314 :
315 8 : dbh->db_records++;
316 8 : if (put_dbf_record(dbh, dbh->db_records, cp) < 0) {
317 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to put record at %ld", dbh->db_records);
318 0 : efree(cp);
319 0 : RETURN_FALSE;
320 : }
321 :
322 8 : put_dbf_info(dbh);
323 8 : efree(cp);
324 :
325 8 : RETURN_TRUE;
326 : }
327 : /* }}} */
328 :
329 : /* {{{ proto bool dbase_replace_record(int identifier, array data, int recnum)
330 : Replaces a record to the database */
331 : PHP_FUNCTION(dbase_replace_record)
332 0 : {
333 : zval **dbh_id, **fields, **field, **recnum;
334 : dbhead_t *dbh;
335 : int dbh_type;
336 :
337 : int num_fields;
338 : dbfield_t *dbf, *cur_f;
339 : char *cp, *t_cp;
340 : int i;
341 : DBase_TLS_VARS;
342 :
343 0 : if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &dbh_id, &fields, &recnum) == FAILURE) {
344 0 : WRONG_PARAM_COUNT;
345 : }
346 0 : convert_to_long_ex(dbh_id);
347 0 : convert_to_long_ex(recnum);
348 0 : if (Z_TYPE_PP(fields) != IS_ARRAY) {
349 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array as second parameter");
350 0 : RETURN_FALSE;
351 : }
352 :
353 0 : dbh = zend_list_find(Z_LVAL_PP(dbh_id), &dbh_type);
354 0 : if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
355 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find database for identifier %ld", Z_LVAL_PP(dbh_id));
356 0 : RETURN_FALSE;
357 : }
358 :
359 0 : num_fields = zend_hash_num_elements(Z_ARRVAL_PP(fields));
360 :
361 0 : if (num_fields != dbh->db_nfields) {
362 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong number of fields specified");
363 0 : RETURN_FALSE;
364 : }
365 :
366 0 : cp = t_cp = (char *)emalloc(dbh->db_rlen + 1);
367 0 : *t_cp++ = VALID_RECORD;
368 :
369 0 : dbf = dbh->db_fields;
370 0 : for (i = 0, cur_f = dbf; cur_f < &dbf[num_fields]; i++, cur_f++) {
371 0 : if (zend_hash_index_find(Z_ARRVAL_PP(fields), i, (void **)&field) == FAILURE) {
372 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unexpected error");
373 0 : efree(cp);
374 0 : RETURN_FALSE;
375 : }
376 0 : convert_to_string_ex(field);
377 0 : snprintf(t_cp, cur_f->db_flen+1, cur_f->db_format, Z_STRVAL_PP(field));
378 0 : t_cp += cur_f->db_flen;
379 : }
380 :
381 0 : if (put_dbf_record(dbh, Z_LVAL_PP(recnum), cp) < 0) {
382 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to put record at %ld", dbh->db_records);
383 0 : efree(cp);
384 0 : RETURN_FALSE;
385 : }
386 :
387 0 : put_dbf_info(dbh);
388 0 : efree(cp);
389 :
390 0 : RETURN_TRUE;
391 : }
392 : /* }}} */
393 :
394 : /* {{{ proto bool dbase_delete_record(int identifier, int record)
395 : Marks a record to be deleted */
396 : PHP_FUNCTION(dbase_delete_record)
397 2 : {
398 : zval **dbh_id, **record;
399 : dbhead_t *dbh;
400 : int dbh_type;
401 : DBase_TLS_VARS;
402 :
403 2 : if (ZEND_NUM_ARGS() != 2 || (zend_get_parameters_ex(2, &dbh_id, &record) == FAILURE)) {
404 0 : WRONG_PARAM_COUNT;
405 : }
406 2 : convert_to_long_ex(dbh_id);
407 2 : convert_to_long_ex(record);
408 :
409 2 : dbh = zend_list_find(Z_LVAL_PP(dbh_id), &dbh_type);
410 2 : if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
411 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find database for identifier %ld", Z_LVAL_PP(dbh_id));
412 0 : RETURN_FALSE;
413 : }
414 :
415 2 : if (del_dbf_record(dbh, Z_LVAL_PP(record)) < 0) {
416 0 : if (Z_LVAL_PP(record) > dbh->db_records) {
417 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "record %ld out of bounds", Z_LVAL_PP(record));
418 : } else {
419 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to delete record %ld", Z_LVAL_PP(record));
420 : }
421 0 : RETURN_FALSE;
422 : }
423 :
424 2 : put_dbf_info(dbh);
425 2 : RETURN_TRUE;
426 : }
427 : /* }}} */
428 :
429 : /* {{{ php_dbase_get_record
430 : */
431 : static void php_dbase_get_record(INTERNAL_FUNCTION_PARAMETERS, int assoc)
432 9 : {
433 : zval **dbh_id, **record;
434 : dbhead_t *dbh;
435 : int dbh_type;
436 : dbfield_t *dbf, *cur_f;
437 : char *data, *fnp, *str_value;
438 9 : size_t cursize = 0;
439 : long overflow_test;
440 : int errno_save;
441 : DBase_TLS_VARS;
442 :
443 9 : if (ZEND_NUM_ARGS() != 2 || (zend_get_parameters_ex(2, &dbh_id, &record) == FAILURE)) {
444 0 : WRONG_PARAM_COUNT;
445 : }
446 9 : convert_to_long_ex(dbh_id);
447 9 : convert_to_long_ex(record);
448 :
449 9 : dbh = zend_list_find(Z_LVAL_PP(dbh_id), &dbh_type);
450 9 : if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
451 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find database for identifier %ld", Z_LVAL_PP(dbh_id));
452 0 : RETURN_FALSE;
453 : }
454 :
455 9 : if ((data = get_dbf_record(dbh, Z_LVAL_PP(record))) == NULL) {
456 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Tried to read bad record %ld", Z_LVAL_PP(record));
457 1 : RETURN_FALSE;
458 : }
459 :
460 8 : dbf = dbh->db_fields;
461 :
462 8 : array_init(return_value);
463 :
464 8 : fnp = NULL;
465 40 : for (cur_f = dbf; cur_f < &dbf[dbh->db_nfields]; cur_f++) {
466 : /* get the value */
467 32 : str_value = (char *)emalloc(cur_f->db_flen + 1);
468 :
469 32 : if(cursize <= (unsigned)cur_f->db_flen) {
470 24 : cursize = cur_f->db_flen + 1;
471 24 : fnp = erealloc(fnp, cursize);
472 : }
473 32 : snprintf(str_value, cursize, cur_f->db_format, get_field_val(data, cur_f, fnp));
474 :
475 : /* now convert it to the right php internal type */
476 32 : switch (cur_f->db_type) {
477 : case 'C':
478 : case 'D':
479 24 : if (!assoc) {
480 18 : add_next_index_string(return_value, str_value, 1);
481 : } else {
482 6 : add_assoc_string(return_value, cur_f->db_fname, str_value, 1);
483 : }
484 24 : break;
485 : case 'I': /* FALLS THROUGH */
486 : case 'N':
487 0 : if (cur_f->db_fdc == 0) {
488 : /* Large integers in dbase can be larger than long */
489 0 : errno_save = errno;
490 0 : overflow_test = strtol(str_value, NULL, 10);
491 0 : if (errno == ERANGE) {
492 : /* If the integer is too large, keep it as string */
493 0 : if (!assoc) {
494 0 : add_next_index_string(return_value, str_value, 1);
495 : } else {
496 0 : add_assoc_string(return_value, cur_f->db_fname, str_value, 1);
497 : }
498 : } else {
499 0 : if (!assoc) {
500 0 : add_next_index_long(return_value, overflow_test);
501 : } else {
502 0 : add_assoc_long(return_value, cur_f->db_fname, overflow_test);
503 : }
504 : }
505 0 : errno = errno_save;
506 : } else {
507 0 : if (!assoc) {
508 0 : add_next_index_double(return_value, atof(str_value));
509 : } else {
510 0 : add_assoc_double(return_value, cur_f->db_fname, atof(str_value));
511 : }
512 : }
513 0 : break;
514 : case 'F':
515 0 : if (!assoc) {
516 0 : add_next_index_double(return_value, atof(str_value));
517 : } else {
518 0 : add_assoc_double(return_value, cur_f->db_fname, atof(str_value));
519 : }
520 0 : break;
521 : case 'L': /* we used to FALL THROUGH, but now we check for T/Y and F/N
522 : and insert 1 or 0, respectively. db_fdc is the number of
523 : decimals, which we don't care about. 3/14/2001 LEW */
524 16 : if ((*str_value == 'T') || (*str_value == 'Y')) {
525 8 : if (!assoc) {
526 6 : add_next_index_long(return_value, strtol("1", NULL, 10));
527 : } else {
528 2 : add_assoc_long(return_value, cur_f->db_fname,strtol("1", NULL, 10));
529 : }
530 : } else {
531 0 : if ((*str_value == 'F') || (*str_value == 'N')) {
532 0 : if (!assoc) {
533 0 : add_next_index_long(return_value, strtol("0", NULL, 10));
534 : } else {
535 0 : add_assoc_long(return_value, cur_f->db_fname,strtol("0", NULL, 10));
536 : }
537 : } else {
538 0 : if (!assoc) {
539 0 : add_next_index_long(return_value, strtol(" ", NULL, 10));
540 : } else {
541 0 : add_assoc_long(return_value, cur_f->db_fname,strtol(" ", NULL, 10));
542 : }
543 : }
544 : }
545 : break;
546 : case 'M':
547 : /* this is a memo field. don't know how to deal with this yet */
548 : break;
549 : default:
550 : /* should deal with this in some way */
551 : break;
552 : }
553 32 : efree(str_value);
554 : }
555 :
556 8 : efree(fnp);
557 :
558 : /* mark whether this record was deleted */
559 8 : if (data[0] == '*') {
560 2 : add_assoc_long(return_value, "deleted", 1);
561 : } else {
562 6 : add_assoc_long(return_value, "deleted", 0);
563 : }
564 :
565 8 : free(data);
566 : }
567 : /* }}} */
568 :
569 : /* {{{ proto array dbase_get_record(int identifier, int record)
570 : Returns an array representing a record from the database */
571 : PHP_FUNCTION(dbase_get_record)
572 7 : {
573 7 : php_dbase_get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
574 7 : }
575 : /* }}} */
576 :
577 : /* From Martin Kuba <makub@aida.inet.cz> */
578 : /* {{{ proto array dbase_get_record_with_names(int identifier, int record)
579 : Returns an associative array representing a record from the database */
580 : PHP_FUNCTION(dbase_get_record_with_names)
581 2 : {
582 2 : php_dbase_get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
583 2 : }
584 : /* }}} */
585 :
586 : /* {{{ proto bool dbase_create(string filename, array fields)
587 : Creates a new dBase-format database file */
588 : PHP_FUNCTION(dbase_create)
589 14 : {
590 : zval **filename, **fields, **field, **value;
591 : int fd;
592 : dbhead_t *dbh;
593 :
594 : int num_fields;
595 : dbfield_t *dbf, *cur_f;
596 : int i, rlen, handle;
597 : DBase_TLS_VARS;
598 :
599 14 : if (ZEND_NUM_ARGS() != 2 || (zend_get_parameters_ex(2, &filename, &fields) == FAILURE)) {
600 0 : WRONG_PARAM_COUNT;
601 : }
602 14 : convert_to_string_ex(filename);
603 :
604 14 : if (Z_TYPE_PP(fields) != IS_ARRAY) {
605 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array as second parameter");
606 2 : RETURN_FALSE;
607 : }
608 :
609 12 : if (PG(safe_mode) && (!php_checkuid(Z_STRVAL_PP(filename), NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
610 0 : RETURN_FALSE;
611 : }
612 :
613 12 : if (php_check_open_basedir(Z_STRVAL_PP(filename) TSRMLS_CC)) {
614 0 : RETURN_FALSE;
615 : }
616 :
617 12 : if ((fd = VCWD_OPEN_MODE(Z_STRVAL_PP(filename), O_BINARY|O_RDWR|O_CREAT, 0644)) < 0) {
618 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create database (%d): %s", errno, strerror(errno));
619 0 : RETURN_FALSE;
620 : }
621 :
622 12 : num_fields = zend_hash_num_elements(Z_ARRVAL_PP(fields));
623 :
624 12 : if (num_fields <= 0) {
625 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create database without fields");
626 1 : RETURN_FALSE;
627 : }
628 :
629 : /* have to use regular malloc() because this gets free()d by
630 : code in the dbase library */
631 11 : dbh = (dbhead_t *)malloc(sizeof(dbhead_t));
632 11 : dbf = (dbfield_t *)malloc(sizeof(dbfield_t) * num_fields);
633 11 : if (!dbh || !dbf) {
634 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to allocate memory for header info");
635 0 : RETURN_FALSE;
636 : }
637 :
638 : /* initialize the header structure */
639 11 : dbh->db_fields = dbf;
640 11 : dbh->db_fd = fd;
641 11 : dbh->db_dbt = DBH_TYPE_NORMAL;
642 11 : strcpy(dbh->db_date, "19930818");
643 11 : dbh->db_records = 0;
644 11 : dbh->db_nfields = num_fields;
645 11 : dbh->db_hlen = sizeof(struct dbf_dhead) + 1 + num_fields * sizeof(struct dbf_dfield);
646 :
647 11 : rlen = 1;
648 : /**
649 : * Patch by greg@darkphoton.com
650 : **/
651 : /* make sure that the db_format entries for all fields are set to NULL to ensure we
652 : don't seg fault if there's an error and we need to call free_dbf_head() before all
653 : fields have been defined. */
654 38 : for (i = 0, cur_f = dbf; i < num_fields; i++, cur_f++) {
655 27 : cur_f->db_format = NULL;
656 : }
657 : /**
658 : * end patch
659 : */
660 :
661 :
662 35 : for (i = 0, cur_f = dbf; i < num_fields; i++, cur_f++) {
663 : /* look up the first field */
664 27 : if (zend_hash_index_find(Z_ARRVAL_PP(fields), i, (void **)&field) == FAILURE) {
665 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to find field %d", i);
666 0 : free_dbf_head(dbh);
667 0 : RETURN_FALSE;
668 : }
669 :
670 27 : if (Z_TYPE_PP (field) != IS_ARRAY) {
671 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "second parameter must be array of arrays");
672 0 : free_dbf_head(dbh);
673 0 : RETURN_FALSE;
674 : }
675 :
676 : /* field name */
677 27 : if (zend_hash_index_find(Z_ARRVAL_PP(field), 0, (void **)&value) == FAILURE) {
678 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "expected field name as first element of list in field %d", i);
679 1 : free_dbf_head(dbh);
680 1 : RETURN_FALSE;
681 : }
682 26 : convert_to_string_ex(value);
683 26 : if (Z_STRLEN_PP(value) > 10 || Z_STRLEN_PP(value) == 0) {
684 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid field name '%s' (must be non-empty and less than or equal to 10 characters)", Z_STRVAL_PP(value));
685 0 : free_dbf_head(dbh);
686 0 : RETURN_FALSE;
687 : }
688 26 : copy_crimp(cur_f->db_fname, Z_STRVAL_PP(value), Z_STRLEN_PP(value));
689 :
690 : /* field type */
691 26 : if (zend_hash_index_find(Z_ARRVAL_PP (field), 1, (void **)&value) == FAILURE) {
692 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "expected field type as second element of list in field %d", i);
693 0 : RETURN_FALSE;
694 : }
695 26 : convert_to_string_ex(value);
696 26 : cur_f->db_type = toupper(*Z_STRVAL_PP(value));
697 :
698 26 : cur_f->db_fdc = 0;
699 :
700 : /* verify the field length */
701 26 : switch (cur_f->db_type) {
702 : case 'L':
703 6 : cur_f->db_flen = 1;
704 6 : break;
705 : case 'M':
706 0 : cur_f->db_flen = 10;
707 0 : dbh->db_dbt = DBH_TYPE_MEMO;
708 : /* should create the memo file here, probably */
709 0 : break;
710 : case 'D':
711 6 : cur_f->db_flen = 8;
712 6 : break;
713 : case 'F':
714 0 : cur_f->db_flen = 20;
715 0 : break;
716 : case 'N':
717 : case 'C':
718 : /* field length */
719 12 : if (zend_hash_index_find(Z_ARRVAL_PP (field), 2, (void **)&value) == FAILURE) {
720 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "expected field length as third element of list in field %d", i);
721 0 : free_dbf_head(dbh);
722 0 : RETURN_FALSE;
723 : }
724 12 : convert_to_long_ex(value);
725 12 : cur_f->db_flen = Z_LVAL_PP(value);
726 :
727 12 : if (cur_f->db_type == 'N') {
728 2 : if (zend_hash_index_find(Z_ARRVAL_PP (field), 3, (void **)&value) == FAILURE) {
729 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "expected field precision as fourth element of list in field %d", i);
730 0 : free_dbf_head(dbh);
731 0 : RETURN_FALSE;
732 : }
733 2 : convert_to_long_ex(value);
734 2 : cur_f->db_fdc = Z_LVAL_PP(value);
735 : }
736 12 : break;
737 : default:
738 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unknown field type '%c'", cur_f->db_type);
739 2 : free_dbf_head(dbh);
740 2 : RETURN_FALSE;
741 : }
742 24 : cur_f->db_foffset = rlen;
743 24 : rlen += cur_f->db_flen;
744 :
745 24 : cur_f->db_format = get_dbf_f_fmt(cur_f);
746 : }
747 :
748 8 : dbh->db_rlen = rlen;
749 8 : put_dbf_info(dbh);
750 :
751 8 : handle = zend_list_insert(dbh, DBase_GLOBAL(le_dbhead));
752 8 : RETURN_LONG(handle);
753 : }
754 : /* }}} */
755 :
756 : /* {{{ arginfo */
757 : static
758 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_open, 0)
759 : ZEND_ARG_INFO(0, name)
760 : ZEND_ARG_INFO(0, mode)
761 : ZEND_END_ARG_INFO()
762 :
763 : static
764 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_close, 0)
765 : ZEND_ARG_INFO(0, identifier)
766 : ZEND_END_ARG_INFO()
767 :
768 : static
769 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_numrecords, 0)
770 : ZEND_ARG_INFO(0, identifier)
771 : ZEND_END_ARG_INFO()
772 :
773 : static
774 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_numfields, 0)
775 : ZEND_ARG_INFO(0, identifier)
776 : ZEND_END_ARG_INFO()
777 :
778 : static
779 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_pack, 0)
780 : ZEND_ARG_INFO(0, identifier)
781 : ZEND_END_ARG_INFO()
782 :
783 : static
784 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_add_record, 0)
785 : ZEND_ARG_INFO(0, identifier)
786 : ZEND_ARG_INFO(0, data) /* ARRAY_INFO(0, data, 0) */
787 : ZEND_END_ARG_INFO()
788 :
789 : static
790 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_replace_record, 0)
791 : ZEND_ARG_INFO(0, identifier)
792 : ZEND_ARG_INFO(0, data) /* ARRAY_INFO(0, data, 0) */
793 : ZEND_ARG_INFO(0, recnum)
794 : ZEND_END_ARG_INFO()
795 :
796 : static
797 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_delete_record, 0)
798 : ZEND_ARG_INFO(0, identifier)
799 : ZEND_ARG_INFO(0, record)
800 : ZEND_END_ARG_INFO()
801 :
802 : static
803 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_get_record, 0)
804 : ZEND_ARG_INFO(0, identifier)
805 : ZEND_ARG_INFO(0, record)
806 : ZEND_END_ARG_INFO()
807 :
808 : static
809 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_get_record_with_names, 0)
810 : ZEND_ARG_INFO(0, identifier)
811 : ZEND_ARG_INFO(0, record)
812 : ZEND_END_ARG_INFO()
813 :
814 : static
815 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_create, 0)
816 : ZEND_ARG_INFO(0, filename)
817 : ZEND_ARG_INFO(0, fields) /* ARRAY_INFO(0, fields, 0) */
818 : ZEND_END_ARG_INFO()
819 :
820 : static
821 : ZEND_BEGIN_ARG_INFO(arginfo_dbase_get_header_info, 0)
822 : ZEND_ARG_INFO(0, database_handle)
823 : ZEND_END_ARG_INFO()
824 :
825 : /* }}} */
826 :
827 : /* {{{ dbase_functions[]
828 : */
829 : zend_function_entry dbase_functions[] = {
830 : PHP_FE(dbase_open, arginfo_dbase_open)
831 : PHP_FE(dbase_create, arginfo_dbase_create)
832 : PHP_FE(dbase_close, arginfo_dbase_close)
833 : PHP_FE(dbase_numrecords, arginfo_dbase_numrecords)
834 : PHP_FE(dbase_numfields, arginfo_dbase_numfields)
835 : PHP_FE(dbase_add_record, arginfo_dbase_add_record)
836 : PHP_FE(dbase_replace_record, arginfo_dbase_replace_record)
837 : PHP_FE(dbase_get_record, arginfo_dbase_get_record)
838 : PHP_FE(dbase_get_record_with_names, arginfo_dbase_get_record_with_names)
839 : PHP_FE(dbase_delete_record, arginfo_dbase_delete_record)
840 : PHP_FE(dbase_pack, arginfo_dbase_pack)
841 : PHP_FE(dbase_get_header_info, arginfo_dbase_get_header_info)
842 : {NULL, NULL, NULL}
843 : };
844 : /* }}} */
845 :
846 : /* Added by Zak Greant <zak@php.net> */
847 : /* {{{ proto array dbase_get_header_info(int database_handle)
848 : */
849 : PHP_FUNCTION(dbase_get_header_info)
850 1 : {
851 : zval **dbh_id, *row;
852 : dbfield_t *dbf, *cur_f;
853 : dbhead_t *dbh;
854 : int dbh_type;
855 : DBase_TLS_VARS;
856 :
857 1 : if (ZEND_NUM_ARGS() != 1 || (zend_get_parameters_ex(1, &dbh_id) == FAILURE)) {
858 0 : WRONG_PARAM_COUNT;
859 : }
860 1 : convert_to_long_ex(dbh_id);
861 :
862 1 : dbh = zend_list_find(Z_LVAL_PP(dbh_id), &dbh_type);
863 1 : if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
864 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find database for identifier %ld", Z_LVAL_PP(dbh_id));
865 0 : RETURN_FALSE;
866 : }
867 :
868 1 : array_init(return_value);
869 :
870 1 : dbf = dbh->db_fields;
871 5 : for (cur_f = dbf; cur_f < &dbh->db_fields[dbh->db_nfields]; ++cur_f) {
872 4 : MAKE_STD_ZVAL(row);
873 4 : array_init(row);
874 :
875 4 : add_next_index_zval(return_value, row);
876 :
877 : /* field name */
878 4 : add_assoc_string(row, "name", cur_f->db_fname, 1);
879 :
880 : /* field type */
881 4 : switch (cur_f->db_type) {
882 2 : case 'C': add_assoc_string(row, "type", "character", 1); break;
883 1 : case 'D': add_assoc_string(row, "type", "date", 1); break;
884 0 : case 'I': add_assoc_string(row, "type", "integer", 1); break;
885 0 : case 'N': add_assoc_string(row, "type", "number", 1); break;
886 1 : case 'L': add_assoc_string(row, "type", "boolean", 1); break;
887 0 : case 'M': add_assoc_string(row, "type", "memo", 1); break;
888 0 : case 'F': add_assoc_string(row, "type", "float", 1); break;
889 0 : default: add_assoc_string(row, "type", "unknown", 1); break;
890 : }
891 :
892 : /* length of field */
893 4 : add_assoc_long(row, "length", cur_f->db_flen);
894 :
895 : /* number of decimals in field */
896 4 : switch (cur_f->db_type) {
897 : case 'N':
898 : case 'I':
899 0 : add_assoc_long(row, "precision", cur_f->db_fdc);
900 0 : break;
901 : default:
902 4 : add_assoc_long(row, "precision", 0);
903 : }
904 :
905 : /* format for printing %s etc */
906 4 : add_assoc_string(row, "format", cur_f->db_format, 1);
907 :
908 : /* offset within record */
909 4 : add_assoc_long(row, "offset", cur_f->db_foffset);
910 : }
911 : }
912 : /* }}} */
913 :
914 : zend_module_entry dbase_module_entry = {
915 : STANDARD_MODULE_HEADER,
916 : "dbase", dbase_functions, PHP_MINIT(dbase), PHP_MSHUTDOWN(dbase), NULL, NULL, NULL, NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
917 : };
918 :
919 :
920 : #ifdef COMPILE_DL_DBASE
921 : ZEND_GET_MODULE(dbase)
922 :
923 : #if defined(PHP_WIN32) && defined(THREAD_SAFE)
924 :
925 : /*NOTE: You should have an odbc.def file where you
926 : export DllMain*/
927 : BOOL WINAPI DllMain(HANDLE hModule,
928 : DWORD ul_reason_for_call,
929 : LPVOID lpReserved)
930 : {
931 : return 1;
932 : }
933 : #endif
934 : #endif
935 :
936 : #endif
937 :
938 : /*
939 : * Local variables:
940 : * tab-width: 4
941 : * c-basic-offset: 4
942 : * End:
943 : * vim600: sw=4 ts=4 fdm=marker
944 : * vim<600: sw=4 ts=4
945 : */
|