php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #53713
Patch session_sqlite3 revision 2011-08-01 05:13 UTC by crrodriguez at opensuse dot org
Patch bugs-53713-sqlite3-session-win32-plus-test revision 2011-05-02 12:07 UTC by jinmoku at hotmail dot com
revision 2011-05-02 12:03 UTC by jinmoku at hotmail dot com
Patch bugs-53713-sqlite3-session.patch revision 2011-05-02 12:05 UTC by jinmoku at hotmail dot com
revision 2011-04-30 02:04 UTC by jinmoku at hotmail dot com

Patch bugs-53713-sqlite3-session-win32-plus-test for SQLite related Bug #53713

Patch version 2011-05-02 12:03 UTC

Return to Bug #53713 | Download this patch
This patch is obsolete

Obsoleted by patches:

Patch Revisions:

Developer: jinmoku@hotmail.com

Index: ext/sqlite3/tests/sqlite3_session_002.phpt
===================================================================
--- ext/sqlite3/tests/sqlite3_session_002.phpt	(revision 0)
+++ ext/sqlite3/tests/sqlite3_session_002.phpt	(revision 0)
@@ -0,0 +1,54 @@
+--TEST--
+sqlite3, session destroy test
+--CREDITS--
+Mats Lindh <mats at lindh.no>
+#Testfest php.no
+--INI--
+session.save_handler = sqlite3
+--SKIPIF--
+if (!extension_loaded("session"))
+{
+	die("skip Session module not loaded");
+}
+if (!extension_loaded("sqlite3"))
+{
+	die("skip sqlite3 module not loaded");
+}
+--FILE--
+<?php
+/* Description: Tests that sqlite will destroy a session when used as a session handler
+* Source code: ext/sqlite/sess_sqlite3.c
+*/
+ob_start();
+session_save_path(__DIR__ . "/sessiondb.sdb");
+
+// start a session and save a value to it before commiting the session to the database
+session_start();
+$_SESSION["test"] = "foo_bar";
+session_write_close();
+
+// remove the session value
+unset($_SESSION["test"]);
+var_dump(isset($_SESSION["test"]));
+
+// start the session again and destroy it
+session_start();
+var_dump($_SESSION["test"]);
+session_destroy();
+session_write_close();
+
+unset($_SESSION["test"]);
+
+// check that the session has been destroyed
+session_start();
+var_dump(isset($_SESSION["test"]));
+ob_end_flush();
+?>
+--EXPECTF--
+bool(false)
+%unicode|string%(7) "foo_bar"
+bool(false)
+--CLEAN--
+<?php
+	unlink(__DIR__ . "/sessiondb.sdb")
+?>
Index: ext/sqlite3/tests/sqlite3_session_001.phpt
===================================================================
--- ext/sqlite3/tests/sqlite3_session_001.phpt	(revision 0)
+++ ext/sqlite3/tests/sqlite3_session_001.phpt	(revision 0)
@@ -0,0 +1,46 @@
+--TEST--
+sqlite3, session storage test
+--CREDITS--
+Mats Lindh <mats at lindh.no>
+#Testfest php.no
+--INI--
+session.save_handler = sqlite3
+--SKIPIF--
+if (!extension_loaded("session"))
+{
+	die("skip Session module not loaded");
+}
+if (!extension_loaded("sqlite3"))
+{
+	die("skip Session module not loaded");
+}
+--FILE--
+<?php
+/* Description: Tests that sqlite can be used as a session save handler
+* Source code: ext/sqlite/sess_sqlite3.c
+*/
+
+ob_start();
+session_save_path(__DIR__ . "/sessiondb.sdb");
+
+// create the session and set a session value
+session_start();
+$_SESSION["test"] = "foo_bar";
+
+// close the session and unset the value
+session_write_close();
+unset($_SESSION["test"]);
+var_dump(isset($_SESSION["test"]));
+
+// start the session again and check that we have the proper value
+session_start();
+var_dump($_SESSION["test"]);
+ob_end_flush();
+?>
+--EXPECTF--
+bool(false)
+%unicode|string%(7) "foo_bar"
+--CLEAN--
+<?php
+	unlink(__DIR__ . "/sessiondb.sdb")
+?>
Index: ext/sqlite3/config.w32
===================================================================
--- ext/sqlite3/config.w32	(revision 310704)
+++ ext/sqlite3/config.w32	(working copy)
@@ -5,7 +5,7 @@
 
 if (PHP_SQLITE3 != "no") {
 	ADD_FLAG("CFLAGS_SQLITE3", "/D SQLITE_THREADSAFE=" + (PHP_ZTS == "yes" ? "1" : "0") + " /D SQLITE_ENABLE_FTS3=1 /D SQLITE_ENABLE_COLUMN_METADATA=1 /D SQLITE_CORE=1 ");
-	EXTENSION("sqlite3", "sqlite3.c", null, "/I" + configure_module_dirname + "/libsqlite /I" + configure_module_dirname);
+	EXTENSION("sqlite3", "sqlite3.c sess_sqlite3.c", null, "/I" + configure_module_dirname + "/libsqlite /I" + configure_module_dirname);
 
 	ADD_SOURCES(configure_module_dirname + "/libsqlite", "sqlite3.c", "sqlite3");
 
Index: ext/sqlite3/sqlite3.c
===================================================================
--- ext/sqlite3/sqlite3.c	(revision 310704)
+++ ext/sqlite3/sqlite3.c	(working copy)
@@ -25,6 +25,9 @@
 #include "php.h"
 #include "php_ini.h"
 #include "ext/standard/info.h"
+#include "ext/standard/info.h"
+#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
+#include "ext/session/php_session.h"
 #include "php_sqlite3.h"
 #include "php_sqlite3_structs.h"
 #include "main/SAPI.h"
@@ -38,6 +41,12 @@
 ZEND_DECLARE_MODULE_GLOBALS(sqlite3)
 
 static PHP_GINIT_FUNCTION(sqlite3);
+
+#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
+extern ps_module ps_mod_sqlite3;
+#define ps_sqlite3_ptr &ps_mod_sqlite3
+#endif
+
 static int php_sqlite3_authorizer(void *autharg, int access_type, const char *arg3, const char *arg4, const char *arg5, const char *arg6);
 static void sqlite3_param_dtor(void *data);
 static int php_sqlite3_compare_stmt_zval_free(php_sqlite3_free_list **free_list, zval *statement);
@@ -2114,6 +2123,10 @@
 	php_sqlite3_result_entry = zend_register_internal_class(&ce TSRMLS_CC);
 
 	REGISTER_INI_ENTRIES();
+	
+#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
+	php_session_register_module(ps_sqlite3_ptr);
+#endif
 
 	REGISTER_LONG_CONSTANT("SQLITE3_ASSOC", PHP_SQLITE3_ASSOC, CONST_CS | CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("SQLITE3_NUM", PHP_SQLITE3_NUM, CONST_CS | CONST_PERSISTENT);
@@ -2165,6 +2178,16 @@
 }
 /* }}} */
 
+/* {{{ sqlite3_module_dep
+*/
+static const zend_module_dep sqlite3_deps[] = {
+#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
+	ZEND_MOD_REQUIRED("session")
+#endif
+	{NULL, NULL, NULL}
+};
+/* }}} */
+
 /* {{{ sqlite3_module_entry
 */
 zend_module_entry sqlite3_module_entry = {
Index: ext/sqlite3/sess_sqlite3.c
===================================================================
--- ext/sqlite3/sess_sqlite3.c	(revision 0)
+++ ext/sqlite3/sess_sqlite3.c	(revision 0)
@@ -0,0 +1,190 @@
+/* 
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2011 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 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_01.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 <john@php.net>                              |
+   |          Wez Furlong <wez@thebrainroom.com>                          |
+   |          Stealth35 <jinmoku@hotmail.com>                             |
+   +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "php.h"
+
+#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
+
+#include "ext/session/php_session.h"
+#include "ext/standard/php_lcg.h"
+#include <sqlite3.h>
+#define SQLITE_RETVAL(__r) ((__r) == SQLITE_OK ? SUCCESS : FAILURE)
+#define PS_SQLITE_DATA sqlite3 *db = (sqlite3*)PS_GET_MOD_DATA()
+
+PS_FUNCS(sqlite3);
+
+extern ps_module ps_mod_sqlite3 = {
+	PS_MOD(sqlite3)
+};
+
+PS_OPEN_FUNC(sqlite3) 
+{
+	int rc;
+	sqlite3 *db;
+
+	/* TODO: do we need a safe_mode check here? */
+	rc = sqlite3_open(save_path, &db);
+	if (rc) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, 
+				"SQLite: failed to open/create session database `%s' - %s", save_path, sqlite3_errmsg(db));
+		return FAILURE;
+	}
+
+	/* allow up to 1 minute when busy */
+	sqlite3_busy_timeout(db, 60000);
+
+	sqlite3_exec(db, "PRAGMA default_synchronous = OFF", NULL, NULL, NULL);
+	sqlite3_exec(db, "PRAGMA count_changes = OFF", NULL, NULL, NULL);
+
+	/* 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. */
+	sqlite3_exec(db, 
+	    "CREATE TABLE session_data ("
+	    "    sess_id PRIMARY KEY," 
+	    "    value TEXT, "
+	    "    updated INTEGER "
+	    ")", NULL, NULL, NULL);
+
+	PS_SET_MOD_DATA(db);
+
+	return SUCCESS;
+}
+
+PS_CLOSE_FUNC(sqlite3) 
+{
+	PS_SQLITE_DATA;
+
+	sqlite3_close(db);
+
+	return SUCCESS;
+}
+
+PS_READ_FUNC(sqlite3) 
+{
+	PS_SQLITE_DATA;
+	char *query;
+	const char *tail;
+	sqlite3_stmt *stmt;
+	int result;
+	const char *rowdata;
+
+	*val = NULL;
+	
+	query = sqlite3_mprintf("SELECT value FROM session_data WHERE sess_id='%q' LIMIT 1", key);
+	if (query == NULL) {
+		/* no memory */
+		return FAILURE;
+	}
+
+	if (sqlite3_prepare(db, query, strlen(query) + 1, &stmt, &tail) != SQLITE_OK) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: Could not compile session read query: %s", sqlite3_errmsg(db));
+		sqlite3_free(query);
+		return FAILURE;
+	}
+
+	result = sqlite3_step(stmt);
+	if(result == SQLITE_ROW) {
+		*vallen = sqlite3_column_bytes(stmt, 0);
+		rowdata  = sqlite3_column_text(stmt, 0);
+		if (*vallen) {
+			*val = emalloc(*vallen);
+			memcpy(*val, rowdata, *vallen);
+			(*val)[*vallen] = '\0';
+		} else {
+			*val = STR_EMPTY_ALLOC();
+		}
+	}
+	
+	if (SQLITE_OK != sqlite3_finalize(stmt)) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: session read: error %s", sqlite3_errmsg(db));
+	}
+
+	sqlite3_free(query);
+	
+	return *val == NULL ? FAILURE : SUCCESS;
+}
+
+PS_WRITE_FUNC(sqlite3) 
+{
+	PS_SQLITE_DATA;
+	char *error;
+	char *query;
+	time_t t;
+	int rv;
+	
+	t = time(NULL);
+	
+	query = sqlite3_mprintf("REPLACE INTO session_data VALUES('%q', '%q', %d)", key, val, t);
+	rv = sqlite3_exec(db, query, NULL, NULL, &error);
+	if (rv != SQLITE_OK) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: session write query failed: %s", error);
+		sqlite3_free(error);
+	}
+	sqlite3_free(query);
+
+	return SQLITE_RETVAL(rv);
+}
+
+PS_DESTROY_FUNC(sqlite3) 
+{
+	char *query;
+	int rv;
+	PS_SQLITE_DATA;
+
+	query = sqlite3_mprintf("DELETE FROM session_data WHERE sess_id='%q'", key);
+	rv = sqlite3_exec(db, query, NULL, NULL, NULL);
+sqlite3_free(query);
+	
+	return SQLITE_RETVAL(rv);
+}
+
+PS_GC_FUNC(sqlite3) 
+{
+	PS_SQLITE_DATA;
+	char *query;
+	int rv;
+	time_t t = time(NULL);
+
+	query = sqlite3_mprintf("DELETE FROM session_data WHERE (%d - updated) > %d", t, maxlifetime);
+	rv = sqlite3_exec(db, query,	NULL, NULL, NULL);
+	sqlite3_free(query);
+
+	/* because SQLite does not actually clear the deleted data from the database 
+	 * we need to occassionaly do so manually to prevent the sessions database 
+	 * from growing endlessly.
+	 */
+	if ((int) ((float) PS(gc_divisor) * PS(gc_divisor) * php_combined_lcg(TSRMLS_C)) < PS(gc_probability)) {
+		rv = sqlite3_exec(db, "VACUUM", NULL, NULL, NULL);
+	}
+	return SQLITE_RETVAL(rv);
+}
+
+#endif /* HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION) */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
\ No newline at end of file
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 02 23:01:29 2024 UTC