1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 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 | Authors: Sascha Schumann <sascha@schumann.cx> |
16 | Marcus Boerger <helly@php.net> |
17 +----------------------------------------------------------------------+
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "php.h"
25
26 #if HAVE_DBA
27
28 #include "php_ini.h"
29 #include <stdio.h>
30 #include <fcntl.h>
31 #ifdef HAVE_SYS_FILE_H
32 #include <sys/file.h>
33 #endif
34
35 #include "php_dba.h"
36 #include "ext/standard/info.h"
37 #include "ext/standard/php_string.h"
38 #include "ext/standard/flock_compat.h"
39
40 #include "php_gdbm.h"
41 #include "php_ndbm.h"
42 #include "php_dbm.h"
43 #include "php_cdb.h"
44 #include "php_db1.h"
45 #include "php_db2.h"
46 #include "php_db3.h"
47 #include "php_db4.h"
48 #include "php_flatfile.h"
49 #include "php_inifile.h"
50 #include "php_qdbm.h"
51 #include "php_tcadb.h"
52 #include "php_lmdb.h"
53
54 /* {{{ arginfo */
55 ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_popen, 0, 0, 2)
56 ZEND_ARG_INFO(0, path)
57 ZEND_ARG_INFO(0, mode)
58 ZEND_ARG_INFO(0, handlername)
59 ZEND_ARG_VARIADIC_INFO(0, handler_parameters)
60 ZEND_END_ARG_INFO()
61
62 ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_open, 0, 0, 2)
63 ZEND_ARG_INFO(0, path)
64 ZEND_ARG_INFO(0, mode)
65 ZEND_ARG_INFO(0, handlername)
66 ZEND_ARG_VARIADIC_INFO(0, handler_parameters)
67 ZEND_END_ARG_INFO()
68
69 ZEND_BEGIN_ARG_INFO(arginfo_dba_close, 0)
70 ZEND_ARG_INFO(0, handle)
71 ZEND_END_ARG_INFO()
72
73 ZEND_BEGIN_ARG_INFO(arginfo_dba_exists, 0)
74 ZEND_ARG_INFO(0, key)
75 ZEND_ARG_INFO(0, handle)
76 ZEND_END_ARG_INFO()
77
78 ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_fetch, 0, 0, 2)
79 ZEND_ARG_INFO(0, key)
80 ZEND_ARG_INFO(0, skip)
81 ZEND_ARG_INFO(0, handle)
82 ZEND_END_ARG_INFO()
83
84 ZEND_BEGIN_ARG_INFO(arginfo_dba_key_split, 0)
85 ZEND_ARG_INFO(0, key)
86 ZEND_END_ARG_INFO()
87
88 ZEND_BEGIN_ARG_INFO(arginfo_dba_firstkey, 0)
89 ZEND_ARG_INFO(0, handle)
90 ZEND_END_ARG_INFO()
91
92 ZEND_BEGIN_ARG_INFO(arginfo_dba_nextkey, 0)
93 ZEND_ARG_INFO(0, handle)
94 ZEND_END_ARG_INFO()
95
96 ZEND_BEGIN_ARG_INFO(arginfo_dba_delete, 0)
97 ZEND_ARG_INFO(0, key)
98 ZEND_ARG_INFO(0, handle)
99 ZEND_END_ARG_INFO()
100
101 ZEND_BEGIN_ARG_INFO(arginfo_dba_insert, 0)
102 ZEND_ARG_INFO(0, key)
103 ZEND_ARG_INFO(0, value)
104 ZEND_ARG_INFO(0, handle)
105 ZEND_END_ARG_INFO()
106
107 ZEND_BEGIN_ARG_INFO(arginfo_dba_replace, 0)
108 ZEND_ARG_INFO(0, key)
109 ZEND_ARG_INFO(0, value)
110 ZEND_ARG_INFO(0, handle)
111 ZEND_END_ARG_INFO()
112
113 ZEND_BEGIN_ARG_INFO(arginfo_dba_optimize, 0)
114 ZEND_ARG_INFO(0, handle)
115 ZEND_END_ARG_INFO()
116
117 ZEND_BEGIN_ARG_INFO(arginfo_dba_sync, 0)
118 ZEND_ARG_INFO(0, handle)
119 ZEND_END_ARG_INFO()
120
121 ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_handlers, 0, 0, 0)
122 ZEND_ARG_INFO(0, full_info)
123 ZEND_END_ARG_INFO()
124
125 ZEND_BEGIN_ARG_INFO(arginfo_dba_list, 0)
126 ZEND_END_ARG_INFO()
127
128 /* }}} */
129
130 /* {{{ dba_functions[]
131 */
132 static const zend_function_entry dba_functions[] = {
133 PHP_FE(dba_open, arginfo_dba_open)
134 PHP_FE(dba_popen, arginfo_dba_popen)
135 PHP_FE(dba_close, arginfo_dba_close)
136 PHP_FE(dba_delete, arginfo_dba_delete)
137 PHP_FE(dba_exists, arginfo_dba_exists)
138 PHP_FE(dba_fetch, arginfo_dba_fetch)
139 PHP_FE(dba_insert, arginfo_dba_insert)
140 PHP_FE(dba_replace, arginfo_dba_replace)
141 PHP_FE(dba_firstkey, arginfo_dba_firstkey)
142 PHP_FE(dba_nextkey, arginfo_dba_nextkey)
143 PHP_FE(dba_optimize, arginfo_dba_optimize)
144 PHP_FE(dba_sync, arginfo_dba_sync)
145 PHP_FE(dba_handlers, arginfo_dba_handlers)
146 PHP_FE(dba_list, arginfo_dba_list)
147 PHP_FE(dba_key_split, arginfo_dba_key_split)
148 PHP_FE_END
149 };
150 /* }}} */
151
152 PHP_MINIT_FUNCTION(dba);
153 PHP_MSHUTDOWN_FUNCTION(dba);
154 PHP_MINFO_FUNCTION(dba);
155
156 ZEND_BEGIN_MODULE_GLOBALS(dba)
157 char *default_handler;
158 dba_handler *default_hptr;
159 ZEND_END_MODULE_GLOBALS(dba)
160
161 ZEND_DECLARE_MODULE_GLOBALS(dba)
162
163 #ifdef ZTS
164 #define DBA_G(v) TSRMG(dba_globals_id, zend_dba_globals *, v)
165 #else
166 #define DBA_G(v) (dba_globals.v)
167 #endif
168
169 static PHP_GINIT_FUNCTION(dba);
170
171 zend_module_entry dba_module_entry = {
172 STANDARD_MODULE_HEADER,
173 "dba",
174 dba_functions,
175 PHP_MINIT(dba),
176 PHP_MSHUTDOWN(dba),
177 NULL,
178 NULL,
179 PHP_MINFO(dba),
180 PHP_DBA_VERSION,
181 PHP_MODULE_GLOBALS(dba),
182 PHP_GINIT(dba),
183 NULL,
184 NULL,
185 STANDARD_MODULE_PROPERTIES_EX
186 };
187
188 #ifdef COMPILE_DL_DBA
ZEND_GET_MODULE(dba)189 ZEND_GET_MODULE(dba)
190 #endif
191
192 /* {{{ macromania */
193
194 #define DBA_ID_PARS \
195 zval *id; \
196 dba_info *info = NULL; \
197 int ac = ZEND_NUM_ARGS()
198
199 /* these are used to get the standard arguments */
200
201 /* {{{ php_dba_myke_key */
202 static size_t php_dba_make_key(zval *key, char **key_str, char **key_free)
203 {
204 if (Z_TYPE_P(key) == IS_ARRAY) {
205 zval *group, *name;
206 HashPosition pos;
207 size_t len;
208
209 if (zend_hash_num_elements(Z_ARRVAL_P(key)) != 2) {
210 zend_throw_error(NULL, "Key does not have exactly two elements: (key, name)");
211 return 0;
212 }
213 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(key), &pos);
214 group = zend_hash_get_current_data_ex(Z_ARRVAL_P(key), &pos);
215 zend_hash_move_forward_ex(Z_ARRVAL_P(key), &pos);
216 name = zend_hash_get_current_data_ex(Z_ARRVAL_P(key), &pos);
217 convert_to_string_ex(group);
218 convert_to_string_ex(name);
219 if (Z_STRLEN_P(group) == 0) {
220 *key_str = Z_STRVAL_P(name);
221 *key_free = NULL;
222 return Z_STRLEN_P(name);
223 }
224 len = spprintf(key_str, 0, "[%s]%s", Z_STRVAL_P(group), Z_STRVAL_P(name));
225 *key_free = *key_str;
226 return len;
227 } else {
228 zval tmp;
229 size_t len;
230
231 ZVAL_COPY(&tmp, key);
232 convert_to_string(&tmp);
233
234 len = Z_STRLEN(tmp);
235 if (len) {
236 *key_free = *key_str = estrndup(Z_STRVAL(tmp), Z_STRLEN(tmp));
237 }
238 zval_ptr_dtor(&tmp);
239 return len;
240 }
241 }
242 /* }}} */
243
244 #define DBA_GET2 \
245 zval *key; \
246 char *key_str, *key_free; \
247 size_t key_len; \
248 if (zend_parse_parameters(ac, "zr", &key, &id) == FAILURE) { \
249 return; \
250 } \
251 if ((key_len = php_dba_make_key(key, &key_str, &key_free)) == 0) {\
252 RETURN_FALSE; \
253 }
254
255 #define DBA_GET2_3 \
256 zval *key; \
257 char *key_str, *key_free; \
258 size_t key_len; \
259 zend_long skip = 0; \
260 switch(ac) { \
261 case 2: \
262 if (zend_parse_parameters(ac, "zr", &key, &id) == FAILURE) { \
263 return; \
264 } \
265 break; \
266 case 3: \
267 if (zend_parse_parameters(ac, "zlr", &key, &skip, &id) == FAILURE) { \
268 return; \
269 } \
270 break; \
271 default: \
272 WRONG_PARAM_COUNT; \
273 } \
274 if ((key_len = php_dba_make_key(key, &key_str, &key_free)) == 0) {\
275 RETURN_FALSE; \
276 }
277
278
279 #define DBA_FETCH_RESOURCE(info, id) \
280 if ((info = (dba_info *)zend_fetch_resource2(Z_RES_P(id), "DBA identifier", le_db, le_pdb)) == NULL) { \
281 RETURN_FALSE; \
282 }
283
284 #define DBA_FETCH_RESOURCE_WITH_ID(info, id) \
285 if ((info = (dba_info *)zend_fetch_resource2(Z_RES_P(id), "DBA identifier", le_db, le_pdb)) == NULL) { \
286 DBA_ID_DONE; \
287 RETURN_FALSE; \
288 }
289
290 #define DBA_ID_GET2 DBA_ID_PARS; DBA_GET2; DBA_FETCH_RESOURCE_WITH_ID(info, id)
291 #define DBA_ID_GET2_3 DBA_ID_PARS; DBA_GET2_3; DBA_FETCH_RESOURCE_WITH_ID(info, id)
292
293 #define DBA_ID_DONE \
294 if (key_free) efree(key_free)
295 /* a DBA handler must have specific routines */
296
297 #define DBA_NAMED_HND(alias, name, flags) \
298 {\
299 #alias, flags, dba_open_##name, dba_close_##name, dba_fetch_##name, dba_update_##name, \
300 dba_exists_##name, dba_delete_##name, dba_firstkey_##name, dba_nextkey_##name, \
301 dba_optimize_##name, dba_sync_##name, dba_info_##name \
302 },
303
304 #define DBA_HND(name, flags) DBA_NAMED_HND(name, name, flags)
305
306 /* check whether the user has write access */
307 #define DBA_WRITE_CHECK \
308 if(info->mode != DBA_WRITER && info->mode != DBA_TRUNC && info->mode != DBA_CREAT) { \
309 php_error_docref(NULL, E_WARNING, "You cannot perform a modification to a database without proper access"); \
310 RETURN_FALSE; \
311 }
312
313 /* the same check, but with a call to DBA_ID_DONE before returning */
314 #define DBA_WRITE_CHECK_WITH_ID \
315 if(info->mode != DBA_WRITER && info->mode != DBA_TRUNC && info->mode != DBA_CREAT) { \
316 php_error_docref(NULL, E_WARNING, "You cannot perform a modification to a database without proper access"); \
317 DBA_ID_DONE; \
318 RETURN_FALSE; \
319 }
320
321 /* }}} */
322
323 /* {{{ globals */
324
325 static dba_handler handler[] = {
326 #if DBA_GDBM
327 DBA_HND(gdbm, DBA_LOCK_EXT) /* Locking done in library if set */
328 #endif
329 #if DBA_DBM
330 DBA_HND(dbm, DBA_LOCK_ALL) /* No lock in lib */
331 #endif
332 #if DBA_NDBM
333 DBA_HND(ndbm, DBA_LOCK_ALL) /* Could be done in library: filemode = 0644 + S_ENFMT */
334 #endif
335 #if DBA_CDB
336 DBA_HND(cdb, DBA_STREAM_OPEN|DBA_LOCK_ALL) /* No lock in lib */
337 #endif
338 #if DBA_CDB_BUILTIN
339 DBA_NAMED_HND(cdb_make, cdb, DBA_STREAM_OPEN|DBA_LOCK_ALL) /* No lock in lib */
340 #endif
341 #if DBA_DB1
342 DBA_HND(db1, DBA_LOCK_ALL) /* No lock in lib */
343 #endif
344 #if DBA_DB2
345 DBA_HND(db2, DBA_LOCK_ALL) /* No lock in lib */
346 #endif
347 #if DBA_DB3
348 DBA_HND(db3, DBA_LOCK_ALL) /* No lock in lib */
349 #endif
350 #if DBA_DB4
351 DBA_HND(db4, DBA_LOCK_ALL) /* No lock in lib */
352 #endif
353 #if DBA_INIFILE
354 DBA_HND(inifile, DBA_STREAM_OPEN|DBA_LOCK_ALL|DBA_CAST_AS_FD) /* No lock in lib */
355 #endif
356 #if DBA_FLATFILE
357 DBA_HND(flatfile, DBA_STREAM_OPEN|DBA_LOCK_ALL|DBA_NO_APPEND) /* No lock in lib */
358 #endif
359 #if DBA_QDBM
360 DBA_HND(qdbm, DBA_LOCK_EXT)
361 #endif
362 #if DBA_TCADB
363 DBA_HND(tcadb, DBA_LOCK_ALL)
364 #endif
365 #if DBA_LMDB
366 DBA_HND(lmdb, DBA_LOCK_EXT)
367 #endif
368 { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
369 };
370
371 #if DBA_FLATFILE
372 #define DBA_DEFAULT "flatfile"
373 #elif DBA_DB4
374 #define DBA_DEFAULT "db4"
375 #elif DBA_DB3
376 #define DBA_DEFAULT "db3"
377 #elif DBA_DB2
378 #define DBA_DEFAULT "db2"
379 #elif DBA_DB1
380 #define DBA_DEFAULT "db1"
381 #elif DBA_GDBM
382 #define DBA_DEFAULT "gdbm"
383 #elif DBA_NBBM
384 #define DBA_DEFAULT "ndbm"
385 #elif DBA_DBM
386 #define DBA_DEFAULT "dbm"
387 #elif DBA_QDBM
388 #define DBA_DEFAULT "qdbm"
389 #elif DBA_TCADB
390 #define DBA_DEFAULT "tcadb"
391 #elif DBA_LMDB
392 #define DBA_DEFAULT "lmdb"
393 #else
394 #define DBA_DEFAULT ""
395 #endif
396 /* cdb/cdb_make and ini are no option here */
397
398 static int le_db;
399 static int le_pdb;
400 /* }}} */
401
402 /* {{{ dba_fetch_resource
403 PHPAPI void dba_fetch_resource(dba_info **pinfo, zval **id)
404 {
405 dba_info *info;
406 DBA_ID_FETCH
407 *pinfo = info;
408 }
409 */
410 /* }}} */
411
412 /* {{{ dba_get_handler
413 PHPAPI dba_handler *dba_get_handler(const char* handler_name)
414 {
415 dba_handler *hptr;
416 for (hptr = handler; hptr->name && strcasecmp(hptr->name, handler_name); hptr++);
417 return hptr;
418 }
419 */
420 /* }}} */
421
422 /* {{{ dba_close
423 */
dba_close(dba_info * info)424 static void dba_close(dba_info *info)
425 {
426 if (info->hnd) {
427 info->hnd->close(info);
428 }
429 if (info->path) {
430 pefree(info->path, info->flags&DBA_PERSISTENT);
431 }
432 if (info->fp && info->fp != info->lock.fp) {
433 if (info->flags & DBA_PERSISTENT) {
434 php_stream_pclose(info->fp);
435 } else {
436 php_stream_close(info->fp);
437 }
438 }
439 if (info->lock.fp) {
440 if (info->flags & DBA_PERSISTENT) {
441 php_stream_pclose(info->lock.fp);
442 } else {
443 php_stream_close(info->lock.fp);
444 }
445 }
446 if (info->lock.name) {
447 pefree(info->lock.name, info->flags&DBA_PERSISTENT);
448 }
449 pefree(info, info->flags&DBA_PERSISTENT);
450 }
451 /* }}} */
452
453 /* {{{ dba_close_rsrc
454 */
dba_close_rsrc(zend_resource * rsrc)455 static void dba_close_rsrc(zend_resource *rsrc)
456 {
457 dba_info *info = (dba_info *)rsrc->ptr;
458
459 dba_close(info);
460 }
461 /* }}} */
462
463 /* {{{ dba_close_pe_rsrc_deleter */
dba_close_pe_rsrc_deleter(zval * el,void * pDba)464 int dba_close_pe_rsrc_deleter(zval *el, void *pDba)
465 {
466 if (Z_RES_P(el)->ptr == pDba) {
467 if (Z_DELREF_P(el) == 0) {
468 return ZEND_HASH_APPLY_REMOVE;
469 } else {
470 return ZEND_HASH_APPLY_KEEP | ZEND_HASH_APPLY_STOP;
471 }
472 } else {
473 return ZEND_HASH_APPLY_KEEP;
474 }
475 }
476 /* }}} */
477
478 /* {{{ dba_close_pe_rsrc */
dba_close_pe_rsrc(zend_resource * rsrc)479 static void dba_close_pe_rsrc(zend_resource *rsrc)
480 {
481 dba_info *info = (dba_info *)rsrc->ptr;
482
483 /* closes the resource by calling dba_close_rsrc() */
484 zend_hash_apply_with_argument(&EG(persistent_list), dba_close_pe_rsrc_deleter, info);
485 }
486 /* }}} */
487
488 /* {{{ PHP_INI
489 */
ZEND_INI_MH(OnUpdateDefaultHandler)490 ZEND_INI_MH(OnUpdateDefaultHandler)
491 {
492 dba_handler *hptr;
493
494 if (!ZSTR_LEN(new_value)) {
495 DBA_G(default_hptr) = NULL;
496 return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
497 }
498
499 for (hptr = handler; hptr->name && strcasecmp(hptr->name, ZSTR_VAL(new_value)); hptr++);
500
501 if (!hptr->name) {
502 php_error_docref(NULL, E_WARNING, "No such handler: %s", ZSTR_VAL(new_value));
503 return FAILURE;
504 }
505 DBA_G(default_hptr) = hptr;
506 return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
507 }
508
509 PHP_INI_BEGIN()
510 STD_PHP_INI_ENTRY("dba.default_handler", DBA_DEFAULT, PHP_INI_ALL, OnUpdateDefaultHandler, default_handler, zend_dba_globals, dba_globals)
PHP_INI_END()511 PHP_INI_END()
512 /* }}} */
513
514 /* {{{ PHP_GINIT_FUNCTION
515 */
516 static PHP_GINIT_FUNCTION(dba)
517 {
518 dba_globals->default_handler = "";
519 dba_globals->default_hptr = NULL;
520 }
521 /* }}} */
522
523 /* {{{ PHP_MINIT_FUNCTION
524 */
PHP_MINIT_FUNCTION(dba)525 PHP_MINIT_FUNCTION(dba)
526 {
527 REGISTER_INI_ENTRIES();
528 le_db = zend_register_list_destructors_ex(dba_close_rsrc, NULL, "dba", module_number);
529 le_pdb = zend_register_list_destructors_ex(dba_close_pe_rsrc, dba_close_rsrc, "dba persistent", module_number);
530 return SUCCESS;
531 }
532 /* }}} */
533
534 /* {{{ PHP_MSHUTDOWN_FUNCTION
535 */
PHP_MSHUTDOWN_FUNCTION(dba)536 PHP_MSHUTDOWN_FUNCTION(dba)
537 {
538 UNREGISTER_INI_ENTRIES();
539 return SUCCESS;
540 }
541 /* }}} */
542
543 #include "zend_smart_str.h"
544
545 /* {{{ PHP_MINFO_FUNCTION
546 */
PHP_MINFO_FUNCTION(dba)547 PHP_MINFO_FUNCTION(dba)
548 {
549 dba_handler *hptr;
550 smart_str handlers = {0};
551
552 for(hptr = handler; hptr->name; hptr++) {
553 smart_str_appends(&handlers, hptr->name);
554 smart_str_appendc(&handlers, ' ');
555 }
556
557 php_info_print_table_start();
558 php_info_print_table_row(2, "DBA support", "enabled");
559 if (handlers.s) {
560 smart_str_0(&handlers);
561 php_info_print_table_row(2, "Supported handlers", ZSTR_VAL(handlers.s));
562 smart_str_free(&handlers);
563 } else {
564 php_info_print_table_row(2, "Supported handlers", "none");
565 }
566 php_info_print_table_end();
567 DISPLAY_INI_ENTRIES();
568 }
569 /* }}} */
570
571 /* {{{ php_dba_update
572 */
php_dba_update(INTERNAL_FUNCTION_PARAMETERS,int mode)573 static void php_dba_update(INTERNAL_FUNCTION_PARAMETERS, int mode)
574 {
575 size_t val_len;
576 zval *id;
577 dba_info *info = NULL;
578 int ac = ZEND_NUM_ARGS();
579 zval *key;
580 char *val;
581 char *key_str, *key_free;
582 size_t key_len;
583
584 if (zend_parse_parameters(ac, "zsr", &key, &val, &val_len, &id) == FAILURE) {
585 return;
586 }
587
588 if ((key_len = php_dba_make_key(key, &key_str, &key_free)) == 0) {
589 RETURN_FALSE;
590 }
591
592 DBA_FETCH_RESOURCE_WITH_ID(info, id);
593
594 DBA_WRITE_CHECK_WITH_ID;
595
596 if (info->hnd->update(info, key_str, key_len, val, val_len, mode) == SUCCESS) {
597 DBA_ID_DONE;
598 RETURN_TRUE;
599 }
600
601 DBA_ID_DONE;
602 RETURN_FALSE;
603 }
604 /* }}} */
605
606 #define FREENOW if(args) {int i; for (i=0; i<ac; i++) { zval_ptr_dtor(&args[i]); } efree(args);} if(key) efree(key)
607
608 /* {{{ php_find_dbm
609 */
php_dba_find(const char * path)610 dba_info *php_dba_find(const char* path)
611 {
612 zend_resource *le;
613 dba_info *info;
614 zend_long numitems, i;
615
616 numitems = zend_hash_next_free_element(&EG(regular_list));
617 for (i=1; i<numitems; i++) {
618 if ((le = zend_hash_index_find_ptr(&EG(regular_list), i)) == NULL) {
619 continue;
620 }
621 if (le->type == le_db || le->type == le_pdb) {
622 info = (dba_info *)(le->ptr);
623 if (!strcmp(info->path, path)) {
624 return (dba_info *)(le->ptr);
625 }
626 }
627 }
628
629 return NULL;
630 }
631 /* }}} */
632
633 /* {{{ php_dba_open
634 */
php_dba_open(INTERNAL_FUNCTION_PARAMETERS,int persistent)635 static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, int persistent)
636 {
637 zval *args = NULL;
638 int ac = ZEND_NUM_ARGS();
639 dba_mode_t modenr;
640 dba_info *info, *other;
641 dba_handler *hptr;
642 char *key = NULL, *error = NULL;
643 size_t keylen = 0;
644 int i;
645 int lock_mode, lock_flag, lock_dbf = 0;
646 char *file_mode;
647 char mode[4], *pmode, *lock_file_mode = NULL;
648 int persistent_flag = persistent ? STREAM_OPEN_PERSISTENT : 0;
649 zend_string *opened_path = NULL;
650 char *lock_name;
651 #ifdef PHP_WIN32
652 zend_bool restarted = 0;
653 zend_bool need_creation = 0;
654 #endif
655
656 if (ac < 2) {
657 WRONG_PARAM_COUNT;
658 }
659
660 /* we pass additional args to the respective handler */
661 args = safe_emalloc(ac, sizeof(zval), 0);
662 if (zend_get_parameters_array_ex(ac, args) != SUCCESS) {
663 efree(args);
664 WRONG_PARAM_COUNT;
665 }
666
667 /* we only take string arguments */
668 for (i = 0; i < ac; i++) {
669 ZVAL_STR(&args[i], zval_get_string(&args[i]));
670 keylen += Z_STRLEN(args[i]);
671 }
672
673 if (persistent) {
674 zend_resource *le;
675
676 /* calculate hash */
677 key = safe_emalloc(keylen, 1, 1);
678 key[keylen] = '\0';
679 keylen = 0;
680
681 for(i = 0; i < ac; i++) {
682 memcpy(key+keylen, Z_STRVAL(args[i]), Z_STRLEN(args[i]));
683 keylen += Z_STRLEN(args[i]);
684 }
685
686 /* try to find if we already have this link in our persistent list */
687 if ((le = zend_hash_str_find_ptr(&EG(persistent_list), key, keylen)) != NULL) {
688 FREENOW;
689
690 if (le->type != le_pdb) {
691 RETURN_FALSE;
692 }
693
694 info = (dba_info *)le->ptr;
695
696 GC_ADDREF(le);
697 RETURN_RES(zend_register_resource(info, le_pdb));
698 return;
699 }
700 }
701
702 if (ac==2) {
703 hptr = DBA_G(default_hptr);
704 if (!hptr) {
705 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "No default handler selected");
706 FREENOW;
707 RETURN_FALSE;
708 }
709 } else {
710 for (hptr = handler; hptr->name && strcasecmp(hptr->name, Z_STRVAL(args[2])); hptr++);
711 }
712
713 if (!hptr->name) {
714 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "No such handler: %s", Z_STRVAL(args[2]));
715 FREENOW;
716 RETURN_FALSE;
717 }
718
719 /* Check mode: [rwnc][fl]?t?
720 * r: Read
721 * w: Write
722 * n: Create/Truncate
723 * c: Create
724 *
725 * d: force lock on database file
726 * l: force lock on lck file
727 * -: ignore locking
728 *
729 * t: test open database, warning if locked
730 */
731 strlcpy(mode, Z_STRVAL(args[1]), sizeof(mode));
732 pmode = &mode[0];
733 if (pmode[0] && (pmode[1]=='d' || pmode[1]=='l' || pmode[1]=='-')) { /* force lock on db file or lck file or disable locking */
734 switch (pmode[1]) {
735 case 'd':
736 lock_dbf = 1;
737 if ((hptr->flags & DBA_LOCK_ALL) == 0) {
738 lock_flag = (hptr->flags & DBA_LOCK_ALL);
739 break;
740 }
741 /* no break */
742 case 'l':
743 lock_flag = DBA_LOCK_ALL;
744 if ((hptr->flags & DBA_LOCK_ALL) == 0) {
745 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_NOTICE, "Handler %s does locking internally", hptr->name);
746 }
747 break;
748 default:
749 case '-':
750 if ((hptr->flags & DBA_LOCK_ALL) == 0) {
751 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Locking cannot be disabled for handler %s", hptr->name);
752 FREENOW;
753 RETURN_FALSE;
754 }
755 lock_flag = 0;
756 break;
757 }
758 } else {
759 lock_flag = (hptr->flags&DBA_LOCK_ALL);
760 lock_dbf = 1;
761 }
762 switch (*pmode++) {
763 case 'r':
764 modenr = DBA_READER;
765 lock_mode = (lock_flag & DBA_LOCK_READER) ? LOCK_SH : 0;
766 file_mode = "r";
767 break;
768 case 'w':
769 modenr = DBA_WRITER;
770 lock_mode = (lock_flag & DBA_LOCK_WRITER) ? LOCK_EX : 0;
771 file_mode = "r+b";
772 break;
773 case 'c': {
774 #ifdef PHP_WIN32
775 if (hptr->flags & (DBA_NO_APPEND|DBA_CAST_AS_FD)) {
776 php_stream_statbuf ssb;
777 need_creation = (SUCCESS != php_stream_stat_path(Z_STRVAL(args[0]), &ssb));
778 }
779 #endif
780 modenr = DBA_CREAT;
781 lock_mode = (lock_flag & DBA_LOCK_CREAT) ? LOCK_EX : 0;
782 if (lock_mode) {
783 if (lock_dbf) {
784 /* the create/append check will be done on the lock
785 * when the lib opens the file it is already created
786 */
787 file_mode = "r+b"; /* read & write, seek 0 */
788 #ifdef PHP_WIN32
789 if (!need_creation) {
790 lock_file_mode = "r+b";
791 } else
792 #endif
793 lock_file_mode = "a+b"; /* append */
794 } else {
795 #ifdef PHP_WIN32
796 if (!need_creation) {
797 file_mode = "r+b";
798 } else
799 #endif
800 file_mode = "a+b"; /* append */
801 lock_file_mode = "w+b"; /* create/truncate */
802 }
803 } else {
804 #ifdef PHP_WIN32
805 if (!need_creation) {
806 file_mode = "r+b";
807 } else
808 #endif
809 file_mode = "a+b";
810 }
811 /* In case of the 'a+b' append mode, the handler is responsible
812 * to handle any rewind problems (see flatfile handler).
813 */
814 break;
815 }
816 case 'n':
817 modenr = DBA_TRUNC;
818 lock_mode = (lock_flag & DBA_LOCK_TRUNC) ? LOCK_EX : 0;
819 file_mode = "w+b";
820 break;
821 default:
822 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Illegal DBA mode");
823 FREENOW;
824 RETURN_FALSE;
825 }
826 if (!lock_file_mode) {
827 lock_file_mode = file_mode;
828 }
829 if (*pmode=='d' || *pmode=='l' || *pmode=='-') {
830 pmode++; /* done already - skip here */
831 }
832 if (*pmode=='t') {
833 pmode++;
834 if (!lock_flag) {
835 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "You cannot combine modifiers - (no lock) and t (test lock)");
836 FREENOW;
837 RETURN_FALSE;
838 }
839 if (!lock_mode) {
840 if ((hptr->flags & DBA_LOCK_ALL) == 0) {
841 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Handler %s uses its own locking which doesn't support mode modifier t (test lock)", hptr->name);
842 FREENOW;
843 RETURN_FALSE;
844 } else {
845 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Handler %s doesn't uses locking for this mode which makes modifier t (test lock) obsolete", hptr->name);
846 FREENOW;
847 RETURN_FALSE;
848 }
849 } else {
850 lock_mode |= LOCK_NB; /* test =: non blocking */
851 }
852 }
853 if (*pmode) {
854 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Illegal DBA mode");
855 FREENOW;
856 RETURN_FALSE;
857 }
858
859 info = pemalloc(sizeof(dba_info), persistent);
860 memset(info, 0, sizeof(dba_info));
861 info->path = pestrdup(Z_STRVAL(args[0]), persistent);
862 info->mode = modenr;
863 info->argc = ac - 3;
864 info->argv = args + 3;
865 info->flags = (hptr->flags & ~DBA_LOCK_ALL) | (lock_flag & DBA_LOCK_ALL) | (persistent ? DBA_PERSISTENT : 0);
866 info->lock.mode = lock_mode;
867
868 /* if any open call is a locking call:
869 * check if we already habe a locking call open that should block this call
870 * the problem is some systems would allow read during write
871 */
872 if (hptr->flags & DBA_LOCK_ALL) {
873 if ((other = php_dba_find(info->path)) != NULL) {
874 if ( ( (lock_mode&LOCK_EX) && (other->lock.mode&(LOCK_EX|LOCK_SH)) )
875 || ( (other->lock.mode&LOCK_EX) && (lock_mode&(LOCK_EX|LOCK_SH)) )
876 ) {
877 error = "Unable to establish lock (database file already open)"; /* force failure exit */
878 }
879 }
880 }
881
882 #ifdef PHP_WIN32
883 restart:
884 #endif
885 if (!error && lock_mode) {
886 if (lock_dbf) {
887 lock_name = Z_STRVAL(args[0]);
888 } else {
889 spprintf(&lock_name, 0, "%s.lck", info->path);
890 if (!strcmp(file_mode, "r")) {
891 /* when in read only mode try to use existing .lck file first */
892 /* do not log errors for .lck file while in read ony mode on .lck file */
893 lock_file_mode = "rb";
894 info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|IGNORE_PATH|persistent_flag, &opened_path);
895 }
896 if (!info->lock.fp) {
897 /* when not in read mode or failed to open .lck file read only. now try again in create(write) mode and log errors */
898 lock_file_mode = "a+b";
899 } else {
900 if (opened_path) {
901 info->lock.name = pestrndup(ZSTR_VAL(opened_path), ZSTR_LEN(opened_path), persistent);
902 zend_string_release_ex(opened_path, 0);
903 }
904 }
905 }
906 if (!info->lock.fp) {
907 info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, &opened_path);
908 if (info->lock.fp) {
909 if (lock_dbf) {
910 /* replace the path info with the real path of the opened file */
911 pefree(info->path, persistent);
912 info->path = pestrndup(ZSTR_VAL(opened_path), ZSTR_LEN(opened_path), persistent);
913 }
914 /* now store the name of the lock */
915 info->lock.name = pestrndup(ZSTR_VAL(opened_path), ZSTR_LEN(opened_path), persistent);
916 zend_string_release_ex(opened_path, 0);
917 }
918 }
919 if (!lock_dbf) {
920 efree(lock_name);
921 }
922 if (!info->lock.fp) {
923 dba_close(info);
924 /* stream operation already wrote an error message */
925 FREENOW;
926 RETURN_FALSE;
927 }
928 if (!php_stream_supports_lock(info->lock.fp)) {
929 error = "Stream does not support locking";
930 }
931 if (php_stream_lock(info->lock.fp, lock_mode)) {
932 error = "Unable to establish lock"; /* force failure exit */
933 }
934 }
935
936 /* centralised open stream for builtin */
937 if (!error && (hptr->flags&DBA_STREAM_OPEN)==DBA_STREAM_OPEN) {
938 if (info->lock.fp && lock_dbf) {
939 info->fp = info->lock.fp; /* use the same stream for locking and database access */
940 } else {
941 info->fp = php_stream_open_wrapper(info->path, file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, NULL);
942 }
943 if (!info->fp) {
944 dba_close(info);
945 /* stream operation already wrote an error message */
946 FREENOW;
947 RETURN_FALSE;
948 }
949 if (hptr->flags & (DBA_NO_APPEND|DBA_CAST_AS_FD)) {
950 /* Needed because some systems do not allow to write to the original
951 * file contents with O_APPEND being set.
952 */
953 if (SUCCESS != php_stream_cast(info->fp, PHP_STREAM_AS_FD, (void*)&info->fd, 1)) {
954 php_error_docref(NULL, E_WARNING, "Could not cast stream");
955 dba_close(info);
956 FREENOW;
957 RETURN_FALSE;
958 #ifdef F_SETFL
959 } else if (modenr == DBA_CREAT) {
960 int flags = fcntl(info->fd, F_GETFL);
961 fcntl(info->fd, F_SETFL, flags & ~O_APPEND);
962 #elif defined(PHP_WIN32)
963 } else if (modenr == DBA_CREAT && need_creation && !restarted) {
964 zend_bool close_both;
965
966 close_both = (info->fp != info->lock.fp);
967 php_stream_close(info->lock.fp);
968 if (close_both) {
969 php_stream_close(info->fp);
970 }
971 info->fp = NULL;
972 info->lock.fp = NULL;
973 info->fd = -1;
974
975 pefree(info->lock.name, persistent);
976
977 lock_file_mode = "r+b";
978
979 restarted = 1;
980 goto restart;
981 #endif
982 }
983 }
984 }
985
986 if (error || hptr->open(info, &error) != SUCCESS) {
987 dba_close(info);
988 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Driver initialization failed for handler: %s%s%s", hptr->name, error?": ":"", error?error:"");
989 FREENOW;
990 RETURN_FALSE;
991 }
992
993 info->hnd = hptr;
994 info->argc = 0;
995 info->argv = NULL;
996
997 if (persistent) {
998 if (zend_register_persistent_resource(key, keylen, info, le_pdb) == NULL) {
999 dba_close(info);
1000 php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Could not register persistent resource");
1001 FREENOW;
1002 RETURN_FALSE;
1003 }
1004 }
1005
1006 RETVAL_RES(zend_register_resource(info, (persistent ? le_pdb : le_db)));
1007 FREENOW;
1008 }
1009 /* }}} */
1010 #undef FREENOW
1011
1012 /* {{{ proto resource dba_popen(string path, string mode [, string handlername, string ...])
1013 Opens path using the specified handler in mode persistently */
PHP_FUNCTION(dba_popen)1014 PHP_FUNCTION(dba_popen)
1015 {
1016 php_dba_open(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1017 }
1018 /* }}} */
1019
1020 /* {{{ proto resource dba_open(string path, string mode [, string handlername, string ...])
1021 Opens path using the specified handler in mode*/
PHP_FUNCTION(dba_open)1022 PHP_FUNCTION(dba_open)
1023 {
1024 php_dba_open(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1025 }
1026 /* }}} */
1027
1028 /* {{{ proto void dba_close(resource handle)
1029 Closes database */
PHP_FUNCTION(dba_close)1030 PHP_FUNCTION(dba_close)
1031 {
1032 zval *id;
1033 dba_info *info = NULL;
1034
1035 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1036 return;
1037 }
1038
1039 DBA_FETCH_RESOURCE(info, id);
1040
1041 zend_list_close(Z_RES_P(id));
1042 }
1043 /* }}} */
1044
1045 /* {{{ proto bool dba_exists(string key, resource handle)
1046 Checks, if the specified key exists */
PHP_FUNCTION(dba_exists)1047 PHP_FUNCTION(dba_exists)
1048 {
1049 DBA_ID_GET2;
1050
1051 if(info->hnd->exists(info, key_str, key_len) == SUCCESS) {
1052 DBA_ID_DONE;
1053 RETURN_TRUE;
1054 }
1055 DBA_ID_DONE;
1056 RETURN_FALSE;
1057 }
1058 /* }}} */
1059
1060 /* {{{ proto string dba_fetch(string key, [int skip ,] resource handle)
1061 Fetches the data associated with key */
PHP_FUNCTION(dba_fetch)1062 PHP_FUNCTION(dba_fetch)
1063 {
1064 char *val;
1065 size_t len = 0;
1066 DBA_ID_GET2_3;
1067
1068 if (ac==3) {
1069 if (!strcmp(info->hnd->name, "cdb")) {
1070 if (skip < 0) {
1071 php_error_docref(NULL, E_NOTICE, "Handler %s accepts only skip values greater than or equal to zero, using skip=0", info->hnd->name);
1072 skip = 0;
1073 }
1074 } else if (!strcmp(info->hnd->name, "inifile")) {
1075 /* "-1" is compareable to 0 but allows a non restrictive
1076 * access which is fater. For example 'inifile' uses this
1077 * to allow faster access when the key was already found
1078 * using firstkey/nextkey. However explicitly setting the
1079 * value to 0 ensures the first value.
1080 */
1081 if (skip < -1) {
1082 php_error_docref(NULL, E_NOTICE, "Handler %s accepts only skip value -1 and greater, using skip=0", info->hnd->name);
1083 skip = 0;
1084 }
1085 } else {
1086 php_error_docref(NULL, E_NOTICE, "Handler %s does not support optional skip parameter, the value will be ignored", info->hnd->name);
1087 skip = 0;
1088 }
1089 } else {
1090 skip = 0;
1091 }
1092 if((val = info->hnd->fetch(info, key_str, key_len, skip, &len)) != NULL) {
1093 DBA_ID_DONE;
1094 RETVAL_STRINGL(val, len);
1095 efree(val);
1096 return;
1097 }
1098 DBA_ID_DONE;
1099 RETURN_FALSE;
1100 }
1101 /* }}} */
1102
1103 /* {{{ proto array|false dba_key_split(string key)
1104 Splits an inifile key into an array of the form array(0=>group,1=>value_name) but returns false if input is false or null */
PHP_FUNCTION(dba_key_split)1105 PHP_FUNCTION(dba_key_split)
1106 {
1107 zval *zkey;
1108 char *key, *name;
1109 size_t key_len;
1110
1111 if (ZEND_NUM_ARGS() != 1) {
1112 WRONG_PARAM_COUNT;
1113 }
1114 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "z", &zkey) == SUCCESS) {
1115 if (Z_TYPE_P(zkey) == IS_NULL || (Z_TYPE_P(zkey) == IS_FALSE)) {
1116 RETURN_BOOL(0);
1117 }
1118 }
1119 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &key, &key_len) == FAILURE) {
1120 RETURN_BOOL(0);
1121 }
1122 array_init(return_value);
1123 if (key[0] == '[' && (name = strchr(key, ']')) != NULL) {
1124 add_next_index_stringl(return_value, key+1, name - (key + 1));
1125 add_next_index_stringl(return_value, name+1, key_len - (name - key + 1));
1126 } else {
1127 add_next_index_stringl(return_value, "", 0);
1128 add_next_index_stringl(return_value, key, key_len);
1129 }
1130 }
1131 /* }}} */
1132
1133 /* {{{ proto string dba_firstkey(resource handle)
1134 Resets the internal key pointer and returns the first key */
PHP_FUNCTION(dba_firstkey)1135 PHP_FUNCTION(dba_firstkey)
1136 {
1137 char *fkey;
1138 size_t len;
1139 zval *id;
1140 dba_info *info = NULL;
1141
1142 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1143 return;
1144 }
1145
1146 DBA_FETCH_RESOURCE(info, id);
1147
1148 fkey = info->hnd->firstkey(info, &len);
1149
1150 if (fkey) {
1151 RETVAL_STRINGL(fkey, len);
1152 efree(fkey);
1153 return;
1154 }
1155
1156 RETURN_FALSE;
1157 }
1158 /* }}} */
1159
1160 /* {{{ proto string dba_nextkey(resource handle)
1161 Returns the next key */
PHP_FUNCTION(dba_nextkey)1162 PHP_FUNCTION(dba_nextkey)
1163 {
1164 char *nkey;
1165 size_t len;
1166 zval *id;
1167 dba_info *info = NULL;
1168
1169 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1170 return;
1171 }
1172
1173 DBA_FETCH_RESOURCE(info, id);
1174
1175 nkey = info->hnd->nextkey(info, &len);
1176
1177 if (nkey) {
1178 RETVAL_STRINGL(nkey, len);
1179 efree(nkey);
1180 return;
1181 }
1182
1183 RETURN_FALSE;
1184 }
1185 /* }}} */
1186
1187 /* {{{ proto bool dba_delete(string key, resource handle)
1188 Deletes the entry associated with key
1189 If inifile: remove all other key lines */
PHP_FUNCTION(dba_delete)1190 PHP_FUNCTION(dba_delete)
1191 {
1192 DBA_ID_GET2;
1193
1194 DBA_WRITE_CHECK_WITH_ID;
1195
1196 if(info->hnd->delete(info, key_str, key_len) == SUCCESS)
1197 {
1198 DBA_ID_DONE;
1199 RETURN_TRUE;
1200 }
1201 DBA_ID_DONE;
1202 RETURN_FALSE;
1203 }
1204 /* }}} */
1205
1206 /* {{{ proto bool dba_insert(string key, string value, resource handle)
1207 If not inifile: Insert value as key, return false, if key exists already
1208 If inifile: Add vakue as key (next instance of key) */
PHP_FUNCTION(dba_insert)1209 PHP_FUNCTION(dba_insert)
1210 {
1211 php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1212 }
1213 /* }}} */
1214
1215 /* {{{ proto bool dba_replace(string key, string value, resource handle)
1216 Inserts value as key, replaces key, if key exists already
1217 If inifile: remove all other key lines */
PHP_FUNCTION(dba_replace)1218 PHP_FUNCTION(dba_replace)
1219 {
1220 php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1221 }
1222 /* }}} */
1223
1224 /* {{{ proto bool dba_optimize(resource handle)
1225 Optimizes (e.g. clean up, vacuum) database */
PHP_FUNCTION(dba_optimize)1226 PHP_FUNCTION(dba_optimize)
1227 {
1228 zval *id;
1229 dba_info *info = NULL;
1230
1231 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1232 return;
1233 }
1234
1235 DBA_FETCH_RESOURCE(info, id);
1236
1237 DBA_WRITE_CHECK;
1238
1239 if (info->hnd->optimize(info) == SUCCESS) {
1240 RETURN_TRUE;
1241 }
1242
1243 RETURN_FALSE;
1244 }
1245 /* }}} */
1246
1247 /* {{{ proto bool dba_sync(resource handle)
1248 Synchronizes database */
PHP_FUNCTION(dba_sync)1249 PHP_FUNCTION(dba_sync)
1250 {
1251 zval *id;
1252 dba_info *info = NULL;
1253
1254 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1255 return;
1256 }
1257
1258 DBA_FETCH_RESOURCE(info, id);
1259
1260 if (info->hnd->sync(info) == SUCCESS) {
1261 RETURN_TRUE;
1262 }
1263
1264 RETURN_FALSE;
1265 }
1266 /* }}} */
1267
1268 /* {{{ proto array dba_handlers([bool full_info])
1269 List configured database handlers */
PHP_FUNCTION(dba_handlers)1270 PHP_FUNCTION(dba_handlers)
1271 {
1272 dba_handler *hptr;
1273 zend_bool full_info = 0;
1274
1275 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &full_info) == FAILURE) {
1276 RETURN_FALSE;
1277 }
1278
1279 array_init(return_value);
1280
1281 for(hptr = handler; hptr->name; hptr++) {
1282 if (full_info) {
1283 // TODO: avoid reallocation ???
1284 char *str = hptr->info(hptr, NULL);
1285 add_assoc_string(return_value, hptr->name, str);
1286 efree(str);
1287 } else {
1288 add_next_index_string(return_value, hptr->name);
1289 }
1290 }
1291 }
1292 /* }}} */
1293
1294 /* {{{ proto array dba_list()
1295 List opened databases */
PHP_FUNCTION(dba_list)1296 PHP_FUNCTION(dba_list)
1297 {
1298 zend_ulong numitems, i;
1299 zend_resource *le;
1300 dba_info *info;
1301
1302 if (zend_parse_parameters_none() == FAILURE) {
1303 RETURN_FALSE;
1304 }
1305
1306 array_init(return_value);
1307
1308 numitems = zend_hash_next_free_element(&EG(regular_list));
1309 for (i=1; i<numitems; i++) {
1310 if ((le = zend_hash_index_find_ptr(&EG(regular_list), i)) == NULL) {
1311 continue;
1312 }
1313 if (le->type == le_db || le->type == le_pdb) {
1314 info = (dba_info *)(le->ptr);
1315 add_index_string(return_value, i, info->path);
1316 }
1317 }
1318 }
1319 /* }}} */
1320
1321 #endif /* HAVE_DBA */
1322
1323 /*
1324 * Local variables:
1325 * tab-width: 4
1326 * c-basic-offset: 4
1327 * End:
1328 * vim600: sw=4 ts=4 fdm=marker
1329 * vim<600: sw=4 ts=4
1330 */
1331