#if HAVE_DBA
#include "ext/standard/flock_compat.h"
+#include "php_ini.h"
#include <stdio.h>
#include <fcntl.h>
#ifdef HAVE_SYS_FILE_H
#include "php_db3.h"
#include "php_db4.h"
#include "php_flatfile.h"
+#include "php_inifile.h"
/* {{{ dba_functions[]
*/
WRONG_PARAM_COUNT; \
}
+/* {{{ php_dba_myke_key */
+static size_t php_dba_make_key(zval **key, char **key_str, char **key_free TSRMLS_DC)
+{
+ if (Z_TYPE_PP(key) == IS_ARRAY) {
+ zval **group, **name;
+ HashPosition pos;
+ size_t len;
+
+ if (zend_hash_num_elements(Z_ARRVAL_PP(key)) != 2) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key does not have exactly two elements: (key, name)");
+ return -1;
+ }
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(key), &pos);
+ zend_hash_get_current_data_ex(Z_ARRVAL_PP(key), (void **) &group, &pos);
+ zend_hash_move_forward_ex(Z_ARRVAL_PP(key), &pos);
+ zend_hash_get_current_data_ex(Z_ARRVAL_PP(key), (void **) &name, &pos);
+ convert_to_string_ex(group);
+ convert_to_string_ex(name);
+ if (Z_STRLEN_PP(group) == 0) {
+ *key_str = Z_STRVAL_PP(name);
+ *key_free = NULL;
+ return Z_STRLEN_PP(name);
+ }
+ len = spprintf(key_str, 0, "[%s]%s", Z_STRVAL_PP(group), Z_STRVAL_PP(name));
+ *key_free = *key_str;
+ return len;
+ } else {
+ convert_to_string_ex(key);
+ *key_str = Z_STRVAL_PP(key);
+ *key_free = NULL;
+ return Z_STRLEN_PP(key);
+ }
+}
+/* }}} */
+
#define DBA_GET2 \
zval **key; \
+ char *key_str, *key_free; \
+ size_t key_len; \
if(ac != 2 || zend_get_parameters_ex(ac, &key, &id) != SUCCESS) { \
WRONG_PARAM_COUNT; \
} \
- convert_to_string_ex(key)
+ if ((key_len = php_dba_make_key(key, &key_str, &key_free TSRMLS_CC)) == 0) {\
+ RETURN_FALSE; \
+ }
#define DBA_GET2_3 \
zval **key; \
+ char *key_str, *key_free; \
+ size_t key_len; \
zval **tmp; \
int skip = 0; \
switch(ac) { \
default: \
WRONG_PARAM_COUNT; \
} \
- convert_to_string_ex(key)
+ if ((key_len = php_dba_make_key(key, &key_str, &key_free TSRMLS_CC)) == 0) {\
+ RETURN_FALSE; \
+ }
+
+#define DBA_GET3 \
+ zval **key, **val; \
+ char *key_str, *key_free; \
+ size_t key_len; \
+ if(ac != 3 || zend_get_parameters_ex(ac, &key, &val, &id) != SUCCESS) { \
+ WRONG_PARAM_COUNT; \
+ } \
+ convert_to_string_ex(val); \
+ if ((key_len = php_dba_make_key(key, &key_str, &key_free TSRMLS_CC)) == 0) {\
+ RETURN_FALSE; \
+ }
#define DBA_ID_GET \
ZEND_FETCH_RESOURCE2(info, dba_info *, id, -1, "DBA identifier", le_db, le_pdb);
#define DBA_ID_GET1 DBA_ID_PARS; DBA_GET1; DBA_ID_GET
#define DBA_ID_GET2 DBA_ID_PARS; DBA_GET2; DBA_ID_GET
#define DBA_ID_GET2_3 DBA_ID_PARS; DBA_GET2_3; DBA_ID_GET
+#define DBA_ID_GET3 DBA_ID_PARS; DBA_GET3; DBA_ID_GET
+#define DBA_ID_DONE \
+ if (key_free) efree(key_free)
/* a DBA handler must have specific routines */
#define DBA_NAMED_HND(alias, name, flags) \
#if DBA_DB4
DBA_HND(db4, DBA_LOCK_ALL) /* No lock in lib */
#endif
+#if DBA_INIFILE
+ DBA_HND(inifile, DBA_STREAM_OPEN|DBA_LOCK_ALL) /* No lock in lib */
+#endif
#if DBA_FLATFILE
DBA_HND(flatfile, DBA_STREAM_OPEN|DBA_LOCK_ALL) /* No lock in lib */
#endif
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
+#if DBA_FLATFILE
+#define DBA_DEFAULT "flatfile"
+#elif DBA_DB4
+#define DBA_DEFAULT "db4"
+#elif DBA_DB3
+#define DBA_DEFAULT "db3"
+#elif DBA_DB2
+#define DBA_DEFAULT "db2"
+#elif DBA_GDBM
+#define DBA_DEFAULT "gdbm"
+#elif DBA_NBBM
+#define DBA_DEFAULT "ndbm"
+#elif DBA_DBM
+#define DBA_DEFAULT "dbm"
+#else
+#define DBA_DEFAULT ""
+#endif
+/* cdb/cdb_make and ini are no option here */
+
+ZEND_BEGIN_MODULE_GLOBALS(dba)
+ char *default_handler;
+ dba_handler *default_hptr;
+ZEND_END_MODULE_GLOBALS(dba)
+
+ZEND_DECLARE_MODULE_GLOBALS(dba)
+
+#ifdef ZTS
+#define DBA_G(v) TSRMG(dba_globals_id, zend_dba_globals *, v)
+#else
+#define DBA_G(v) (dba_globals.v)
+#endif
+
static int le_db;
static int le_pdb;
+
+/* {{{ dba_fetch_resource
+PHPAPI void dba_fetch_resource(dba_info **pinfo, zval **id TSRMLS_DC)
+{
+ dba_info *info;
+ DBA_ID_FETCH
+ *pinfo = info;
+}
+*/
+/* }}} */
+
+/* {{{ dba_get_handler
+PHPAPI dba_handler *dba_get_handler(const char* handler_name)
+{
+ dba_handler *hptr;
+ for (hptr = handler; hptr->name && strcasecmp(hptr->name, handler_name); hptr++);
+ return hptr;
+}
+*/
/* }}} */
/* {{{ dba_close
}
/* }}} */
+/* {{{ PHP_INI
+ */
+ZEND_API ZEND_INI_MH(OnUpdateDefaultHandler)
+{
+ dba_handler *hptr;
+
+ if (!strlen(new_value)) {
+ DBA_G(default_hptr) = NULL;
+ return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
+ }
+
+ for (hptr = handler; hptr->name && strcasecmp(hptr->name, new_value); hptr++);
+
+ if (!hptr->name) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such handler: %s", new_value);
+ return FAILURE;
+ }
+ DBA_G(default_hptr) = hptr;
+ return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
+}
+
+PHP_INI_BEGIN()
+ STD_PHP_INI_ENTRY("dba.default_handler", DBA_DEFAULT, PHP_INI_ALL, OnUpdateDefaultHandler, default_handler, zend_dba_globals, dba_globals)
+PHP_INI_END()
+/* }}} */
+
+/* {{{ php_dba_init_globals
+ */
+static void php_dba_init_globals(zend_dba_globals *dba_globals)
+{
+ dba_globals->default_handler = "";
+ dba_globals->default_hptr = NULL;
+}
+/* }}} */
+
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(dba)
{
+ ZEND_INIT_MODULE_GLOBALS(dba, php_dba_init_globals, NULL);
+ REGISTER_INI_ENTRIES();
le_db = zend_register_list_destructors_ex(dba_close_rsrc, NULL, "dba", module_number);
le_pdb = zend_register_list_destructors_ex(dba_close_pe_rsrc, dba_close_rsrc, "dba persistent", module_number);
return SUCCESS;
*/
PHP_MSHUTDOWN_FUNCTION(dba)
{
+ UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
*/
static void php_dba_update(INTERNAL_FUNCTION_PARAMETERS, int mode)
{
- DBA_ID_PARS;
- zval **val, **key;
char *v;
int len;
-
- if(ac != 3 || zend_get_parameters_ex(ac, &key, &val, &id) != SUCCESS) {
- WRONG_PARAM_COUNT;
- }
- convert_to_string_ex(key);
- convert_to_string_ex(val);
- DBA_ID_GET;
+ DBA_ID_GET3;
DBA_WRITE_CHECK;
len = Z_STRLEN_PP(val);
v = estrndup(Z_STRVAL_PP(val), len);
php_stripslashes(v, &len TSRMLS_CC);
- if(info->hnd->update(info, VALLEN(key), v, len, mode TSRMLS_CC) == SUCCESS) {
+ if(info->hnd->update(info, key_str, key_len, v, len, mode TSRMLS_CC) == SUCCESS) {
efree(v);
+ DBA_ID_DONE;
RETURN_TRUE;
}
efree(v);
} else {
- if(info->hnd->update(info, VALLEN(key), VALLEN(val), mode TSRMLS_CC) == SUCCESS)
+ if(info->hnd->update(info, key_str, key_len, VALLEN(val), mode TSRMLS_CC) == SUCCESS)
+ {
+ DBA_ID_DONE;
RETURN_TRUE;
+ }
}
+ DBA_ID_DONE;
RETURN_FALSE;
}
/* }}} */
char mode[4], *pmode, *lock_file_mode = NULL;
int persistent_flag = persistent ? STREAM_OPEN_PERSISTENT : 0;
- if(ac < 3) {
+ if(ac < 2) {
WRONG_PARAM_COUNT;
}
list_entry *le;
/* calculate hash */
- key = emalloc(keylen);
+ key = safe_emalloc(keylen, 1, 1);
+ key[keylen] = '\0';
keylen = 0;
for(i = 0; i < ac; i++) {
}
}
- for (hptr = handler; hptr->name && strcasecmp(hptr->name, Z_STRVAL_PP(args[2])); hptr++);
+ if (ac==2) {
+ hptr = DBA_G(default_hptr);
+ if (!hptr) {
+ php_error_docref2(NULL TSRMLS_CC, Z_STRVAL_PP(args[0]), Z_STRVAL_PP(args[1]), E_WARNING, "No default handler selected");
+ FREENOW;
+ RETURN_FALSE;
+ }
+ } else {
+ for (hptr = handler; hptr->name && strcasecmp(hptr->name, Z_STRVAL_PP(args[2])); hptr++);
+ }
if (!hptr->name) {
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]));
/* }}} */
#undef FREENOW
-/* {{{ proto int dba_popen(string path, string mode, string handlername [, string ...])
+/* {{{ proto int dba_popen(string path, string mode [, string handlername, string ...])
Opens path using the specified handler in mode persistently */
PHP_FUNCTION(dba_popen)
{
}
/* }}} */
-/* {{{ proto int dba_open(string path, string mode, string handlername [, string ...])
+/* {{{ proto int dba_open(string path, string mode [, string handlername, string ...])
Opens path using the specified handler in mode*/
PHP_FUNCTION(dba_open)
{
{
DBA_ID_GET2;
- if(info->hnd->exists(info, VALLEN(key) TSRMLS_CC) == SUCCESS) {
+ if(info->hnd->exists(info, key_str, key_len TSRMLS_CC) == SUCCESS) {
+ DBA_ID_DONE;
RETURN_TRUE;
}
+ DBA_ID_DONE;
RETURN_FALSE;
}
/* }}} */
int len = 0;
DBA_ID_GET2_3;
- if (ac==3 && strcmp(info->hnd->name, "cdb")) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Handler %s does not support optional skip parameter", info->hnd->name);
+ if (ac==3) {
+ if (!strcmp(info->hnd->name, "cdb")) {
+ if (skip < 0) {
+ 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);
+ skip = 0;
+ }
+ } else if (!strcmp(info->hnd->name, "inifile")) {
+ /* "-1" is compareable to 0 but allows a non restrictive
+ * access which is fater. For example 'inifile' uses this
+ * to allow faster access when the key was already found
+ * using firstkey/nextkey. However explicitly setting the
+ * value to 0 ensures the first value.
+ */
+ if (skip < -1) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Handler %s accepts only skip value -1 and greater, using skip=0", info->hnd->name);
+ skip = 0;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Handler %s does not support optional skip parameter, the value will be ignored", info->hnd->name);
+ skip = 0;
+ }
+ } else {
+ skip = 0;
}
- if((val = info->hnd->fetch(info, VALLEN(key), skip, &len TSRMLS_CC)) != NULL) {
+ if((val = info->hnd->fetch(info, key_str, key_len, skip, &len TSRMLS_CC)) != NULL) {
if (val && PG(magic_quotes_runtime)) {
val = php_addslashes(val, len, &len, 1 TSRMLS_CC);
}
+ DBA_ID_DONE;
RETURN_STRINGL(val, len, 0);
}
+ DBA_ID_DONE;
RETURN_FALSE;
}
/* }}} */
/* }}} */
/* {{{ proto bool dba_delete(string key, int handle)
- Deletes the entry associated with key */
+ Deletes the entry associated with key
+ If inifile: remove all other key lines */
PHP_FUNCTION(dba_delete)
{
DBA_ID_GET2;
DBA_WRITE_CHECK;
- if(info->hnd->delete(info, VALLEN(key) TSRMLS_CC) == SUCCESS)
+ if(info->hnd->delete(info, key_str, key_len TSRMLS_CC) == SUCCESS)
+ {
+ DBA_ID_DONE;
RETURN_TRUE;
+ }
+ DBA_ID_DONE;
RETURN_FALSE;
}
/* }}} */
/* {{{ proto bool dba_insert(string key, string value, int handle)
- Inserts value as key, returns false, if key exists already */
+ If not inifile: Insert value as key, return false, if key exists already
+ If inifile: Add vakue as key (next instance of key) */
PHP_FUNCTION(dba_insert)
{
php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
/* }}} */
/* {{{ proto bool dba_replace(string key, string value, int handle)
- Inserts value as key, replaces key, if key exists already */
+ Inserts value as key, replaces key, if key exists already
+ If inifile: remove all other key lines */
PHP_FUNCTION(dba_replace)
{
php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);