summaryrefslogtreecommitdiff
path: root/ext/session
diff options
context:
space:
mode:
Diffstat (limited to 'ext/session')
-rw-r--r--ext/session/php_session.h1
-rw-r--r--ext/session/session.c130
-rw-r--r--ext/session/tests/session_abort_basic.phpt51
-rw-r--r--ext/session/tests/session_gc_basic.phpt56
-rw-r--r--ext/session/tests/session_hash_function_basic.phpt52
-rw-r--r--ext/session/tests/session_reset_basic.phpt49
-rw-r--r--ext/session/tests/session_serializer_name_basic.phpt37
-rw-r--r--ext/session/tests/session_set_save_handler_basic.phpt3
-rw-r--r--ext/session/tests/session_set_save_handler_class_003.phpt5
-rw-r--r--ext/session/tests/session_set_save_handler_class_007.phpt3
-rw-r--r--ext/session/tests/session_set_save_handler_closures.phpt7
-rw-r--r--ext/session/tests/session_set_save_handler_write_short_circuit.phpt104
12 files changed, 492 insertions, 6 deletions
diff --git a/ext/session/php_session.h b/ext/session/php_session.h
index e8e79f0fa6..4307e6afc5 100644
--- a/ext/session/php_session.h
+++ b/ext/session/php_session.h
@@ -180,6 +180,7 @@ typedef struct _php_ps_globals {
double rfc1867_min_freq; /* session.upload_progress.min_freq */
zend_bool use_strict_mode; /* whether or not PHP accepts unknown session ids */
+ unsigned char session_data_hash[16]; /* binary MD5 hash length */
} php_ps_globals;
typedef php_ps_globals zend_ps_globals;
diff --git a/ext/session/session.c b/ext/session/session.c
index 7bb6584621..5b4820a65c 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -505,8 +505,17 @@ static void php_session_initialize(TSRMLS_D) /* {{{ */
*/
}
if (val) {
+ PHP_MD5_CTX context;
+
+ /* Store read data's MD5 hash */
+ PHP_MD5Init(&context);
+ PHP_MD5Update(&context, val, vallen);
+ PHP_MD5Final(PS(session_data_hash), &context);
+
php_session_decode(val, vallen TSRMLS_CC);
efree(val);
+ } else {
+ memset(PS(session_data_hash),'\0', 16);
}
if (!PS(use_cookies) && PS(send_cookie)) {
@@ -529,7 +538,19 @@ static void php_session_save_current_state(TSRMLS_D) /* {{{ */
val = php_session_encode(&vallen TSRMLS_CC);
if (val) {
- ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, vallen TSRMLS_CC);
+ PHP_MD5_CTX context;
+ unsigned char digest[16];
+
+ /* Generate data's MD5 hash */
+ PHP_MD5Init(&context);
+ PHP_MD5Update(&context, val, vallen);
+ PHP_MD5Final(digest, &context);
+ /* Write only when save is required */
+ if (memcmp(digest, PS(session_data_hash), 16)) {
+ ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, vallen TSRMLS_CC);
+ } else {
+ ret = SUCCESS;
+ }
efree(val);
} else {
ret = PS(mod)->s_write(&PS(mod_data), PS(id), "", 0 TSRMLS_CC);
@@ -727,6 +748,7 @@ static PHP_INI_MH(OnUpdateHashFunc) /* {{{ */
}
#endif /* HAVE_HASH_EXT }}} */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "session.configuration 'session.hash_function' must be existing hash function. %s does not exist.", new_value);
return FAILURE;
}
/* }}} */
@@ -1567,6 +1589,26 @@ static void php_session_flush(TSRMLS_D) /* {{{ */
}
/* }}} */
+static void php_session_abort(TSRMLS_D) /* {{{ */
+{
+ if (PS(session_status) == php_session_active) {
+ PS(session_status) = php_session_none;
+ if (PS(mod_data) || PS(mod_user_implemented)) {
+ PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
+ }
+ }
+}
+/* }}} */
+
+static void php_session_reset(TSRMLS_D) /* {{{ */
+{
+ if (PS(session_status) == php_session_active) {
+ php_session_initialize(TSRMLS_C);
+ }
+}
+/* }}} */
+
+
PHPAPI void session_adapt_url(const char *url, size_t urllen, char **new, size_t *newlen TSRMLS_DC) /* {{{ */
{
if (PS(apply_trans_sid) && (PS(session_status) == php_session_active)) {
@@ -1685,6 +1727,31 @@ static PHP_FUNCTION(session_module_name)
}
/* }}} */
+/* {{{ proto mixed session_serializer_name([string newname])
+ Return the current serializer name used for encode/decode session data. If newname is given, the serialzer name is replaced with newname and return bool */
+static PHP_FUNCTION(session_serializer_name)
+{
+ char *name = NULL;
+ int name_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
+ return;
+ }
+
+ /* Return serializer name */
+ if (!name) {
+ RETURN_STRING(zend_ini_string("session.serialize_handler", sizeof("session.serialize_handler"), 0), 1);
+ }
+
+ /* Set serializer name */
+ if (zend_alter_ini_entry("session.serialize_handler", sizeof("session.serialize_handler"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == SUCCESS) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
/* {{{ proto void session_set_save_handler(string open, string close, string read, string write, string destroy, string gc, string create_sid)
Sets user-level functions */
static PHP_FUNCTION(session_set_save_handler)
@@ -2048,6 +2115,22 @@ static PHP_FUNCTION(session_write_close)
}
/* }}} */
+/* {{{ proto void session_abort(void)
+ Abort session and end session. Session data will not be written */
+static PHP_FUNCTION(session_abort)
+{
+ php_session_abort(TSRMLS_C);
+}
+/* }}} */
+
+/* {{{ proto void session_reset(void)
+ Reset session data from saved session data */
+static PHP_FUNCTION(session_reset)
+{
+ php_session_reset(TSRMLS_C);
+}
+/* }}} */
+
/* {{{ proto int session_status(void)
Returns the current session status */
static PHP_FUNCTION(session_status)
@@ -2060,6 +2143,39 @@ static PHP_FUNCTION(session_status)
}
/* }}} */
+/* {{{ proto int session_gc([int maxlifetime])
+ Execute garbage collection returns number of deleted data */
+static PHP_FUNCTION(session_gc)
+{
+ int nrdels = -1;
+ long maxlifetime = PS(gc_maxlifetime);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &maxlifetime) == FAILURE) {
+ return;
+ }
+
+ /* Session must be active to have PS(mod) */
+ if (PS(session_status) != php_session_active) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Trying to garbage collect without active session");
+ RETURN_FALSE;
+ }
+
+ if (!PS(mod) || !PS(mod)->s_gc) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session save handler does not have gc()");
+ RETURN_FALSE;
+ }
+ PS(mod)->s_gc(&PS(mod_data), maxlifetime, &nrdels TSRMLS_CC);
+
+ if (nrdels < 0) {
+ /* Files save handler return -1 if there is not a permission to remove.
+ Save handlder should return negative nrdels when something wrong. */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session gc failed. Check permission or session storage");
+ RETURN_FALSE;
+ }
+ RETURN_LONG((long)nrdels);
+}
+/* }}} */
+
/* {{{ proto void session_register_shutdown(void)
Registers session_write_close() as a shutdown function */
static PHP_FUNCTION(session_register_shutdown)
@@ -2106,6 +2222,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_session_module_name, 0, 0, 0)
ZEND_ARG_INFO(0, module)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_session_serializer_name, 0, 0, 0)
+ ZEND_ARG_INFO(0, module)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO_EX(arginfo_session_save_path, 0, 0, 0)
ZEND_ARG_INFO(0, path)
ZEND_END_ARG_INFO()
@@ -2151,6 +2271,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_session_set_cookie_params, 0, 0, 1)
ZEND_ARG_INFO(0, httponly)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO(arginfo_session_gc, 0)
+ ZEND_ARG_INFO(0, maxlifetime)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO(arginfo_session_class_open, 0)
ZEND_ARG_INFO(0, save_path)
ZEND_ARG_INFO(0, session_name)
@@ -2185,6 +2309,7 @@ ZEND_END_ARG_INFO()
static const zend_function_entry session_functions[] = {
PHP_FE(session_name, arginfo_session_name)
PHP_FE(session_module_name, arginfo_session_module_name)
+ PHP_FE(session_serializer_name, arginfo_session_serializer_name)
PHP_FE(session_save_path, arginfo_session_save_path)
PHP_FE(session_id, arginfo_session_id)
PHP_FE(session_regenerate_id, arginfo_session_regenerate_id)
@@ -2199,7 +2324,10 @@ static const zend_function_entry session_functions[] = {
PHP_FE(session_set_cookie_params, arginfo_session_set_cookie_params)
PHP_FE(session_get_cookie_params, arginfo_session_void)
PHP_FE(session_write_close, arginfo_session_void)
+ PHP_FE(session_abort, arginfo_session_void)
+ PHP_FE(session_reset, arginfo_session_void)
PHP_FE(session_status, arginfo_session_void)
+ PHP_FE(session_gc, arginfo_session_gc)
PHP_FE(session_register_shutdown, arginfo_session_void)
PHP_FALIAS(session_commit, session_write_close, arginfo_session_void)
PHP_FE_END
diff --git a/ext/session/tests/session_abort_basic.phpt b/ext/session/tests/session_abort_basic.phpt
new file mode 100644
index 0000000000..4a6702f0dc
--- /dev/null
+++ b/ext/session/tests/session_abort_basic.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Test session_abort() function : basic functionality
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--INI--
+session.save_path=
+session.name=PHPSESSID
+--FILE--
+<?php
+
+ob_start();
+
+/*
+ * Prototype : void session_abort(void)
+ * Description : Should abort session. Session data should not be written.
+ * Source code : ext/session/session.c
+ */
+
+echo "*** Testing session_abort() : basic functionality ***\n";
+
+session_start();
+$session_id = session_id();
+$_SESSION['foo'] = 123;
+session_commit();
+
+session_id($session_id);
+session_start();
+$_SESSION['bar'] = 456;
+var_dump($_SESSION);
+session_abort();
+
+session_id($session_id);
+session_start();
+var_dump($_SESSION); // Should only have 'foo'
+
+echo "Done".PHP_EOL;
+
+?>
+--EXPECTF--
+*** Testing session_abort() : basic functionality ***
+array(2) {
+ ["foo"]=>
+ int(123)
+ ["bar"]=>
+ int(456)
+}
+array(1) {
+ ["foo"]=>
+ int(123)
+}
+Done
diff --git a/ext/session/tests/session_gc_basic.phpt b/ext/session/tests/session_gc_basic.phpt
new file mode 100644
index 0000000000..f0726ce93b
--- /dev/null
+++ b/ext/session/tests/session_gc_basic.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Test session_gc() function : basic functionality
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--INI--
+session.serialize_handler=php
+session.save_handler=files
+session.maxlifetime=782000
+--FILE--
+<?php
+error_reporting(E_ALL);
+
+ob_start();
+
+/*
+ * Prototype : int session_gc([int maxlifetime])
+ * Description : Execute gc and return number of deleted data
+ * Source code : ext/session/session.c
+ */
+
+echo "*** Testing session_gc() : basic functionality ***\n";
+
+// Should fail. It requires active session.
+var_dump(session_gc());
+
+session_start();
+// Should succeed with some number
+var_dump(session_gc());
+// Secound time must be int(0)
+var_dump(session_gc());
+session_write_close();
+
+// Start&stop session to generate
+session_start();
+session_write_close();
+session_start();
+session_write_close();
+session_start();
+session_write_close();
+
+session_start();
+$ndeleted = session_gc(0); // Delete all
+var_dump($ndeleted >= 3);
+
+echo "Done".PHP_EOL;
+
+?>
+--EXPECTF--
+*** Testing session_gc() : basic functionality ***
+
+Warning: session_gc(): Trying to garbage collect without active session in %s on line 15
+bool(false)
+int(%d)
+int(0)
+bool(true)
+Done
diff --git a/ext/session/tests/session_hash_function_basic.phpt b/ext/session/tests/session_hash_function_basic.phpt
new file mode 100644
index 0000000000..663852d9d1
--- /dev/null
+++ b/ext/session/tests/session_hash_function_basic.phpt
@@ -0,0 +1,52 @@
+--TEST--
+Test session.hash_function ini setting : basic functionality
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--INI--
+session.hash_bits_per_character=4
+--FILE--
+<?php
+
+ob_start();
+
+echo "*** Testing session.hash_function : basic functionality ***\n";
+
+var_dump(ini_set('session.hash_function', 'md5'));
+var_dump(session_start());
+var_dump(!empty(session_id()), session_id());
+var_dump(session_destroy());
+
+var_dump(ini_set('session.hash_function', 'sha1'));
+var_dump(session_start());
+var_dump(!empty(session_id()), session_id());
+var_dump(session_destroy());
+
+var_dump(ini_set('session.hash_function', 'none')); // Should fail
+var_dump(session_start());
+var_dump(!empty(session_id()), session_id());
+var_dump(session_destroy());
+
+
+echo "Done";
+ob_end_flush();
+?>
+--EXPECTF--
+*** Testing session.hash_function : basic functionality ***
+string(1) "0"
+bool(true)
+bool(true)
+string(32) "%s"
+bool(true)
+string(3) "md5"
+bool(true)
+bool(true)
+string(40) "%s"
+bool(true)
+
+Warning: ini_set(): session.configuration 'session.hash_function' must be existing hash function. none does not exist. in %s/session_hash_function_basic.php on line 17
+bool(false)
+bool(true)
+bool(true)
+string(40) "%s"
+bool(true)
+Done
diff --git a/ext/session/tests/session_reset_basic.phpt b/ext/session/tests/session_reset_basic.phpt
new file mode 100644
index 0000000000..75c6a04119
--- /dev/null
+++ b/ext/session/tests/session_reset_basic.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Test session_reset() function : basic functionality
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--INI--
+session.save_path=
+session.name=PHPSESSID
+--FILE--
+<?php
+
+ob_start();
+
+/*
+ * Prototype : void session_reset(void)
+ * Description : Should abort session. Session data should not be written.
+ * Source code : ext/session/session.c
+ */
+
+echo "*** Testing session_abort() : basic functionality ***\n";
+
+session_start();
+$session_id = session_id();
+$_SESSION['foo'] = 123;
+session_commit();
+
+session_id($session_id);
+session_start();
+$_SESSION['bar'] = 456;
+var_dump($_SESSION);
+session_reset();
+
+var_dump($_SESSION); // Should only have 'foo'
+
+echo "Done".PHP_EOL;
+
+?>
+--EXPECTF--
+*** Testing session_abort() : basic functionality ***
+array(2) {
+ ["foo"]=>
+ int(123)
+ ["bar"]=>
+ int(456)
+}
+array(1) {
+ ["foo"]=>
+ int(123)
+}
+Done
diff --git a/ext/session/tests/session_serializer_name_basic.phpt b/ext/session/tests/session_serializer_name_basic.phpt
new file mode 100644
index 0000000000..ca292dd36f
--- /dev/null
+++ b/ext/session/tests/session_serializer_name_basic.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Test session_serializer_name() function : basic functionality
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--FILE--
+<?php
+
+ob_start();
+
+/*
+ * Prototype : mixed session_serializer_name([string name])
+ * Description : Change/get serialize handler name
+ * Source code : ext/session/session.c
+ */
+
+echo "*** Testing session_serializer_name() : basic functionality ***\n";
+
+var_dump(session_serializer_name());
+var_dump(session_serializer_name('php'));
+var_dump(session_serializer_name('php_binary'));
+var_dump(session_serializer_name('none'));
+var_dump(session_serializer_name());
+
+echo "Done";
+ob_end_flush();
+?>
+--EXPECTF--
+*** Testing session_serializer_name() : basic functionality ***
+string(3) "php"
+bool(true)
+bool(true)
+
+Warning: session_serializer_name(): Cannot find serialization handler 'none' in %s/session_serializer_name_basic.php on line 16
+bool(false)
+string(10) "php_binary"
+Done
+
diff --git a/ext/session/tests/session_set_save_handler_basic.phpt b/ext/session/tests/session_set_save_handler_basic.phpt
index 3897ba9a92..e8496e8afb 100644
--- a/ext/session/tests/session_set_save_handler_basic.phpt
+++ b/ext/session/tests/session_set_save_handler_basic.phpt
@@ -43,6 +43,7 @@ session_id($session_id);
session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
session_start();
var_dump($_SESSION);
+$_SESSION['Bar'] = 'Foo';
session_write_close();
ob_end_flush();
@@ -91,5 +92,5 @@ array(3) {
["Guff"]=>
int(1234567890)
}
-Write [%s,%s,Blah|s:12:"Hello World!";Foo|b:0;Guff|i:1234567890;]
+Write [%s,%s,Blah|s:12:"Hello World!";Foo|b:0;Guff|i:1234567890;Bar|s:3:"Foo";]
Close [%s,PHPSESSID]
diff --git a/ext/session/tests/session_set_save_handler_class_003.phpt b/ext/session/tests/session_set_save_handler_class_003.phpt
index e9a3cc2feb..29b3846851 100644
--- a/ext/session/tests/session_set_save_handler_class_003.phpt
+++ b/ext/session/tests/session_set_save_handler_class_003.phpt
@@ -58,6 +58,7 @@ session_set_save_handler($handler);
session_start();
+$_SESSION['bar'] = 'hello';
session_write_close();
session_unset();
@@ -71,8 +72,10 @@ array(1) {
}
int(4)
string(%d) "%s"
-array(1) {
+array(2) {
["foo"]=>
string(5) "hello"
+ ["bar"]=>
+ string(5) "hello"
}
string(3) "hai"
diff --git a/ext/session/tests/session_set_save_handler_class_007.phpt b/ext/session/tests/session_set_save_handler_class_007.phpt
index 7344ae1ef3..55f722515e 100644
--- a/ext/session/tests/session_set_save_handler_class_007.phpt
+++ b/ext/session/tests/session_set_save_handler_class_007.phpt
@@ -56,6 +56,7 @@ $handler = new MySession(2);
session_set_save_handler($handler);
session_start();
+$_SESSION['abc'] = 'xyz';
// implicit close (called by shutdown function)
echo "done\n";
ob_end_flush();
@@ -69,6 +70,6 @@ ob_end_flush();
(#2) constructor called
(#1) destructor called
done
-(#2) writing %s = foo|s:3:"bar";
+(#2) writing %s = foo|s:3:"bar";abc|s:3:"xyz";
(#2) closing %s
(#2) destructor called
diff --git a/ext/session/tests/session_set_save_handler_closures.phpt b/ext/session/tests/session_set_save_handler_closures.phpt
index 21b2c68737..1251886b01 100644
--- a/ext/session/tests/session_set_save_handler_closures.phpt
+++ b/ext/session/tests/session_set_save_handler_closures.phpt
@@ -42,6 +42,7 @@ echo "Starting session again..!\n";
session_id($session_id);
session_set_save_handler($open_closure, $close_closure, $read_closure, $write_closure, $destroy_closure, $gc_closure);
session_start();
+$_SESSION['Bar'] = 'Foo';
var_dump($_SESSION);
session_write_close();
@@ -83,13 +84,15 @@ array(3) {
Starting session again..!
Open [%s,PHPSESSID]
Read [%s,%s]
-array(3) {
+array(4) {
["Blah"]=>
string(12) "Hello World!"
["Foo"]=>
bool(false)
["Guff"]=>
int(1234567890)
+ ["Bar"]=>
+ string(3) "Foo"
}
-Write [%s,%s,Blah|s:12:"Hello World!";Foo|b:0;Guff|i:1234567890;]
+Write [%s,%s,Blah|s:12:"Hello World!";Foo|b:0;Guff|i:1234567890;Bar|s:3:"Foo";]
Close [%s,PHPSESSID]
diff --git a/ext/session/tests/session_set_save_handler_write_short_circuit.phpt b/ext/session/tests/session_set_save_handler_write_short_circuit.phpt
new file mode 100644
index 0000000000..02ca182ec6
--- /dev/null
+++ b/ext/session/tests/session_set_save_handler_write_short_circuit.phpt
@@ -0,0 +1,104 @@
+--TEST--
+Test session_set_save_handler() function : test write short circuit
+--INI--
+session.save_path=
+session.name=PHPSESSID
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--FILE--
+<?php
+
+ob_start();
+
+/*
+ * Prototype : bool session_set_save_handler(callback $open, callback $close, callback $read, callback $write, callback $destroy, callback $gc)
+ * Description : Sets user-level session storage functions
+ * Source code : ext/session/session.c
+ */
+
+echo "*** Testing session_set_save_handler() : test write short circuit ***\n";
+
+require_once "save_handler.inc";
+$path = dirname(__FILE__);
+session_save_path($path);
+session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
+
+session_start();
+$session_id = session_id();
+$_SESSION["Blah"] = "Hello World!";
+$_SESSION["Foo"] = FALSE;
+$_SESSION["Guff"] = 1234567890;
+var_dump($_SESSION);
+
+session_write_close();
+session_unset();
+var_dump($_SESSION);
+
+echo "Starting session again..!\n";
+session_id($session_id);
+session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
+session_start();
+var_dump($_SESSION);
+$_SESSION['Bar'] = 'Foo';
+session_write_close();
+
+echo "Starting session again..!\n";
+session_id($session_id);
+session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
+session_start();
+var_dump($_SESSION);
+// $_SESSION should be the same and should skip write()
+session_write_close();
+
+ob_end_flush();
+?>
+--EXPECTF--
+*** Testing session_set_save_handler() : test write short circuit ***
+
+Open [%s,PHPSESSID]
+Read [%s,%s]
+array(3) {
+ ["Blah"]=>
+ string(12) "Hello World!"
+ ["Foo"]=>
+ bool(false)
+ ["Guff"]=>
+ int(1234567890)
+}
+Write [%s,%s,Blah|s:12:"Hello World!";Foo|b:0;Guff|i:1234567890;]
+Close [%s,PHPSESSID]
+array(3) {
+ ["Blah"]=>
+ string(12) "Hello World!"
+ ["Foo"]=>
+ bool(false)
+ ["Guff"]=>
+ int(1234567890)
+}
+Starting session again..!
+Open [%s,PHPSESSID]
+Read [%s,%s]
+array(3) {
+ ["Blah"]=>
+ string(12) "Hello World!"
+ ["Foo"]=>
+ bool(false)
+ ["Guff"]=>
+ int(1234567890)
+}
+Write [%s,%s,Blah|s:12:"Hello World!";Foo|b:0;Guff|i:1234567890;Bar|s:3:"Foo";]
+Close [%s,PHPSESSID]
+Starting session again..!
+Open [%s,PHPSESSID]
+Read [%s,%s]
+array(4) {
+ ["Blah"]=>
+ string(12) "Hello World!"
+ ["Foo"]=>
+ bool(false)
+ ["Guff"]=>
+ int(1234567890)
+ ["Bar"]=>
+ string(3) "Foo"
+}
+Close [%s,PHPSESSID] \ No newline at end of file