From: Wez Furlong Date: Tue, 1 Jul 2003 13:07:37 +0000 (+0000) Subject: Add sqlite session handler. X-Git-Tag: BEFORE_ARG_INFO~492 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=607b6501ed7e896fbbe6039b355c04c64c2b274d;p=php Add sqlite session handler. Modified (quite a bit!) patch from John Coggeshall. It compiles, but it otherwise untested. session.save_path == path to actual database file for the session. eg: session.save_path=/tmp/mysite-session.db --- diff --git a/ext/sqlite/config.m4 b/ext/sqlite/config.m4 index 5cdc859f79..7dbd88e617 100644 --- a/ext/sqlite/config.m4 +++ b/ext/sqlite/config.m4 @@ -43,7 +43,7 @@ if test "$PHP_SQLITE" != "no"; then ]) PHP_SUBST(SQLITE_SHARED_LIBADD) - PHP_NEW_EXTENSION(sqlite, sqlite.c libsqlite/src/encode.c, $ext_shared) + PHP_NEW_EXTENSION(sqlite, sqlite.c sess_sqlite.c libsqlite/src/encode.c, $ext_shared) else # use bundled library @@ -62,7 +62,7 @@ if test "$PHP_SQLITE" != "no"; then libsqlite/src/vacuum.c libsqlite/src/copy.c \ libsqlite/src/where.c libsqlite/src/trigger.c" - PHP_NEW_EXTENSION(sqlite, sqlite.c $sources, $ext_shared,,$PHP_SQLITE_CFLAGS) + PHP_NEW_EXTENSION(sqlite, sqlite.c sess_sqlite.c $sources, $ext_shared,,$PHP_SQLITE_CFLAGS) PHP_ADD_BUILD_DIR($ext_builddir/libsqlite) PHP_ADD_BUILD_DIR($ext_builddir/libsqlite/src) AC_CHECK_SIZEOF(char *,4) diff --git a/ext/sqlite/sess_sqlite.c b/ext/sqlite/sess_sqlite.c new file mode 100644 index 0000000000..3abcee0296 --- /dev/null +++ b/ext/sqlite/sess_sqlite.c @@ -0,0 +1,213 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 4 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2003 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: John Coggeshall | + | Wez Furlong | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#include "php.h" +#include "ext/session/php_session.h" +#include + +#define PS_SQLITE_DATA sqlite *db = (sqlite*)PS_GET_MOD_DATA() +extern int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out); +extern int sqlite_decode_binary(const unsigned char *in, unsigned char *out); + +#define CREATE_TBL_QUERY "CREATE TABLE session_data(sess_id TEXT PRIMARY KEY, value TEXT, updated INTEGER)" +#define INSERT_QUERY "REPLACE INTO session_data VALUES('%q', '%q', %d)" +#define SELECT_QUERY "SELECT value FROM session_data WHERE sess_id='%q' LIMIT 1" +#define GC_QUERY "DELETE FROM session_data WHERE (%d - updated) > %d" +#define DELETE_QUERY "DELETE FROM session_data WHERE sess_id='%q'" + +PS_FUNCS(sqlite); + +ps_module ps_mod_sqlite = { + PS_MOD(sqlite) +}; + +/* If you change the logic here, please also update the error message in + * ps_sqlite_open() appropriately (code taken from ps_files_valid_key()) */ + +static int ps_sqlite_valid_key(const char *key) +{ + size_t len; + const char *p; + char c; + int ret = 1; + + for (p = key; (c = *p); p++) { + /* valid characters are a..z,A..Z,0..9 */ + if (!((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || c == ',' + || c == '-')) { + ret = 0; + break; + } + } + + len = p - key; + + if (len == 0) + ret = 0; + + return ret; +} + +PS_OPEN_FUNC(sqlite) +{ + char *filepath; + char *errmsg = NULL; + int spath_len, sname_len, fp_len; + sqlite *db; + + /* TODO: do we need a safe_mode check here? */ + db = sqlite_open(save_path, 0666, &errmsg); + if (db == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: failed to open/create session database `%s' - %s", save_path, errmsg); + sqlite_freemem(errmsg); + return FAILURE; + } + + /* allow up to 1 minute when busy */ + sqlite_busy_timeout(db, 60000); + + /* This will fail if the table already exists, but that's not a big problem. I'm + unclear as to how to check for a table's existence in SQLite -- that would be better here. */ + sqlite_exec(db, CREATE_TBL_QUERY, NULL, NULL, NULL); + + PS_SET_MOD_DATA(db); + + return SUCCESS; +} + +PS_CLOSE_FUNC(sqlite) +{ + PS_SQLITE_DATA; + + sqlite_close(db); + + return SUCCESS; +} + +PS_READ_FUNC(sqlite) +{ + PS_SQLITE_DATA; + char *query; + sqlite_vm *vm; + int colcount, result; + const char **rowdata, **colnames; + char *error; + + if (!ps_sqlite_valid_key(key)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: The session id contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,'"); + return FAILURE; + } + + query = sqlite_mprintf(SELECT_QUERY, key); + if (query == NULL) { + /* no memory */ + return FAILURE; + } + + if (sqlite_compile(db, query, NULL, &vm, &error) != SQLITE_OK) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: Could not compile session read query: %s", error); + sqlite_freemem(error); + sqlite_freemem(query); + return FAILURE; + } + + switch ((result = sqlite_step(vm, &colcount, &rowdata, &colnames))) { + case SQLITE_ROW: + if (rowdata[0] == NULL) { + *vallen = 0; + *val = NULL; + } else { + *vallen = strlen(rowdata[0]); + *val = emalloc(*vallen); + *vallen = sqlite_decode_binary(rowdata[0], *val); + (*val)[*vallen] = '\0'; + } + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: session read query failed: %s", error); + sqlite_freemem(error); + error = NULL; + } + + if (SQLITE_OK != sqlite_finalize(vm, &error)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: session read: error %s", error); + sqlite_freemem(error); + error = NULL; + } + + sqlite_freemem(query); + + return *val == NULL ? FAILURE : SUCCESS; +} + +PS_WRITE_FUNC(sqlite) +{ + PS_SQLITE_DATA; + char *error; + int result = SUCCESS; + time_t t; + char *binary; + int binlen; + + t = time(NULL); + + binary = emalloc((256 * vallen + 1262) / 253); + binlen = sqlite_encode_binary((const unsigned char*)val, vallen, binary); + + if (SQLITE_OK != sqlite_exec_printf(db, INSERT_QUERY, NULL, NULL, &error, key, binary, t)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: session write query failed: %s", error); + sqlite_freemem(error); + result = FAILURE; + } + + efree(binary); + + return result; +} + +PS_DESTROY_FUNC(sqlite) +{ + PS_SQLITE_DATA; + + return SQLITE_OK == sqlite_exec_printf(db, DELETE_QUERY, NULL, NULL, NULL, key) ? + SUCCESS : FAILURE; +} + +PS_GC_FUNC(sqlite) +{ + PS_SQLITE_DATA; + time_t t = time(NULL); + + return SQLITE_OK == sqlite_exec_printf(db, GC_QUERY, NULL, NULL, NULL, t, maxlifetime) ? + SUCCESS : FAILURE; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/ext/sqlite/sqlite.c b/ext/sqlite/sqlite.c index de60030cf2..9e14e68575 100644 --- a/ext/sqlite/sqlite.c +++ b/ext/sqlite/sqlite.c @@ -29,6 +29,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" +#include "ext/session/php_session.h" #include "php_sqlite.h" #if HAVE_TIME_H @@ -57,6 +58,9 @@ ZEND_DECLARE_MODULE_GLOBALS(sqlite) +extern ps_module ps_mod_sqlite; +#define ps_sqlite_ptr &ps_mod_sqlite + extern int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out); extern int sqlite_decode_binary(const unsigned char *in, unsigned char *out); @@ -878,6 +882,8 @@ PHP_MINIT_FUNCTION(sqlite) REGISTER_INI_ENTRIES(); + php_session_register_module(ps_sqlite_ptr); + le_sqlite_db = zend_register_list_destructors_ex(php_sqlite_db_dtor, NULL, "sqlite database", module_number); le_sqlite_pdb = zend_register_list_destructors_ex(NULL, php_sqlite_db_dtor, "sqlite database (persistent)", module_number); le_sqlite_result = zend_register_list_destructors_ex(php_sqlite_result_dtor, NULL, "sqlite result", module_number);