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