From 0431f0700f204ab9941a4791c887024aa4f83ceb Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Wed, 20 Aug 2003 19:19:13 +0000
Subject: [PATCH] - Committed Jeremy's session patch: this brings us one step
 closer to having   session for anonymous users.

---
 CHANGELOG                |  4 ++++
 database/database.mssql  | 13 ++++++++++---
 database/database.mysql  | 19 ++++++++++++++++---
 database/database.pgsql  | 16 +++++++++++++---
 includes/common.inc      |  4 ++++
 modules/user.module      | 37 ++++++++++++++++++++++++++++++++-----
 modules/user/user.module | 37 ++++++++++++++++++++++++++++++++-----
 update.php               | 20 +++++++++++++++++++-
 8 files changed, 130 insertions(+), 20 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 4ca451bc7c12..531e6ff474b9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,10 @@ Drupal x.x.x, xxxx-xx-xx (to be released)
 - comment module:
     * changed the comment module to use the standard pager and rewrote the
       comment housekeeping code to be much more efficient.
+- user module:
+    * added support for multiple sessions per user.
+- forum module:
+    * improved the forum views and the themability thereof.
 - usability improvements:
     * added support for "mass node operations" to ease repetitive tasks.
 
diff --git a/database/database.mssql b/database/database.mssql
index 25eb3a1f996a..25aee614358e 100644
--- a/database/database.mssql
+++ b/database/database.mssql
@@ -252,6 +252,16 @@ CREATE TABLE [dbo].[search_index] (
 ) ON [PRIMARY]
 GO
 
+CREATE TABLE sessions (
+  [sid] [varchar] (32) NOT NULL,
+  [uid] [int] NOT NULL,
+  [hostname] [varchar] (128) NOT NULL,
+  [timestamp] [integer] NOT NULL,
+  [session] [text],
+) ON [PRIMARY]
+GO
+
+
 CREATE TABLE [dbo].[sequences] (
   [name] [varchar] (255) NOT NULL ,
   [id] [numeric](10, 0) NOT NULL
@@ -333,14 +343,11 @@ CREATE TABLE [dbo].[users] (
   [theme] [varchar] (255) NULL ,
   [signature] [varchar] (255) NULL ,
   [timestamp] [float] NOT NULL ,
-  [hostname] [varchar] (128) NULL ,
   [status] [smallint] NOT NULL ,
   [timezone] [varchar] (8) NULL ,
   [rating] [float] NULL ,
   [language] [char] (2) NULL ,
-  [sid] [varchar] (128) NULL ,
   [init] [varchar] (128) NULL ,
-  [session] [text] NULL ,
   [data] [varchar] (8000) NULL ,
   [rid] [int] NOT NULL
 ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
diff --git a/database/database.mysql b/database/database.mysql
index 523aa6181e11..00d6ca884e35 100644
--- a/database/database.mysql
+++ b/database/database.mysql
@@ -360,6 +360,22 @@ CREATE TABLE search_index (
   KEY word (word)
 ) TYPE=MyISAM;
 
+--
+-- Table structure for table 'sessesions'
+--
+
+
+CREATE TABLE sessions (
+  uid int(10) unsigned NOT NULL,
+  sid varchar(32) NOT NULL default '',
+  hostname varchar(128) NOT NULL default '',
+  timestamp int(11) NOT NULL default '0',
+  session text,
+  KEY uid (uid),
+  KEY sid (sid(4)),
+  KEY timestamp (timestamp)
+) TYPE=MyISAM;
+
 --
 -- Table structure for table 'sequences'
 --
@@ -491,14 +507,11 @@ CREATE TABLE users (
   theme varchar(255) NOT NULL default '',
   signature varchar(255) NOT NULL default '',
   timestamp int(11) NOT NULL default '0',
-  hostname varchar(128) NOT NULL default '',
   status tinyint(4) NOT NULL default '0',
   timezone varchar(8) default NULL,
   rating decimal(8,2) default NULL,
   language char(2) NOT NULL default '',
-  sid varchar(32) NOT NULL default '',
   init varchar(64) default '',
-  session text,
   data text,
   rid int(10) unsigned NOT NULL default '0',
   PRIMARY KEY  (uid),
diff --git a/database/database.pgsql b/database/database.pgsql
index 63ec8f7d4372..dc08bfc86857 100644
--- a/database/database.pgsql
+++ b/database/database.pgsql
@@ -360,6 +360,19 @@ CREATE TABLE search_index (
 CREATE INDEX search_index_lno_idx ON search_index(lno);
 CREATE INDEX search_index_word_idx ON search_index(word);
 
+--
+-- Table structure for sessions
+--
+
+CREATE TABLE sessions (
+  uid integer NOT NULL,
+  sid varchar(32) NOT NULL default '',
+  hostname varchar(128) NOT NULL default '',
+  timestamp integer NOT NULL default '0',
+  session text,
+  PRIMARY KEY (sid)
+);
+
 --
 -- Table structure for sequences
 -- This is only used under MySQL, co commented out
@@ -494,14 +507,11 @@ CREATE TABLE users (
   theme varchar(255) NOT NULL default '',
   signature varchar(255) NOT NULL default '',
   timestamp integer NOT NULL default '0',
-  hostname varchar(128) NOT NULL default '',
   status smallint NOT NULL default '0',
   timezone varchar(8) default NULL,
   rating decimal(8,2) default NULL,
   language char(2) NOT NULL default '',
-  sid varchar(32) NOT NULL default '',
   init varchar(64) default '',
-  session text default '',
   data text default '',
   rid integer NOT NULL default '0',
   PRIMARY KEY  (uid),
diff --git a/includes/common.inc b/includes/common.inc
index e0b2f3283591..60a383603f6a 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -248,6 +248,9 @@ function table($header, $rows) {
   if (is_array($header)) {
     $output .= " <tr>";
     foreach ($header as $cell) {
+      if (is_array($cell) && $cell["field"]) {
+        $cell = tablesort($cell, $header);
+      }
       $output .= table_cell($cell, 1);
     }
     $output .= " </tr>\n";
@@ -1096,6 +1099,7 @@ function drupal_page_footer() {
 include_once "includes/pager.inc";
 include_once "includes/menu.inc";
 include_once "includes/xmlrpc.inc";
+include_once "includes/tablesort.inc";
 
 // initialize configuration variables, using values from conf.php if available:
 $conf = variable_init(isset($conf) ? $conf : array());
diff --git a/modules/user.module b/modules/user.module
index f579fb2ffe8f..c05bec7c52ee 100644
--- a/modules/user.module
+++ b/modules/user.module
@@ -22,25 +22,39 @@ function sess_close() {
 
 function sess_read($key) {
   global $user;
-  $user = user_load(array("sid" => $key, "status" => 1));
+
+  $result = db_query_range("SELECT u.*, s.*, r.name AS role FROM {users} u INNER JOIN {role} r ON u.rid = r.rid INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = '". check_query($key) ."' AND u.status < 3", 0, 1);
+  $user = db_fetch_object($result);
 
   return !empty($user->session) ? $user->session : '';
 }
 
 function sess_write($key, $value) {
 
-  db_query("UPDATE {users} SET hostname = '%s', session = '%s', timestamp = %d WHERE sid = '$key'", $_SERVER["REMOTE_ADDR"], $value, time());
+  db_query("UPDATE {sessions} SET hostname = '%s', session = '%s', timestamp = %d WHERE sid = '$key'", $_SERVER["REMOTE_ADDR"], $value, time());
 
   return '';
 }
 
 function sess_destroy($key) {
 
-  db_query("UPDATE {users} SET hostname = '%s', timestamp = %d, sid = '' WHERE sid = '$key'", $_SERVER["REMOTE_ADDR"], time());
+  db_query("DELETE FROM {sessions} WHERE sid = '$key'");
+
 }
 
 function sess_gc($lifetime) {
+
+  /*
+  **  Be sure to adjust 'php_value session.gc_maxlifetime' to a large enough
+  **   value.  For example, if you want user sessions to stay in your database
+  **   for three weeks before deleting them, you need to set gc_maxlifetime
+  **   to '1814400'.  At that value, only after a user doesn't log in after
+  **   three weeks (1814400 seconds) will his/her session be removed.
+  */
+  db_query("DELETE FROM {sessions} WHERE timestamp < %d", time() - $lifetime);
+
   return 1;
+
 }
 
 /*** Common functions ******************************************************/
@@ -313,7 +327,7 @@ function user_fields() {
   }
 
   // Make sure we return the default fields at least
-  return is_array($fields) ? $fields: array("uid", "name", "pass", "mail", "homepage", "mode", "sort", "threshold", "theme", "signature", "timestamp", "hostname", "status", "timezone", "rating", "language", "sid", "init", "session", "data", "rid");
+  return is_array($fields) ? $fields: array("uid", "name", "pass", "mail", "homepage", "mode", "sort", "threshold", "theme", "signature", "timestamp", "status", "timezone", "rating", "language", "init", "data", "rid");
 }
 
 /*** Module hooks **********************************************************/
@@ -618,9 +632,22 @@ function user_login($edit = array(), $msg = "") {
 
       /*
       ** Write session ID to database:
+      **  (TODO: Currently we only save the session if a user is logged in.
+      **   we should also add support for anonymous user sessions.)
       */
 
-      user_save($user, array("sid" => session_id()));
+      if ($user->uid) {
+        // update the user's session if it already exists
+        db_query("UPDATE sessions SET timestamp = '%d' WHERE sid = '%s'", time(), session_id());
+
+        // if no changes, this is a new session to be added
+        if (!db_affected_rows()) {
+          db_query("INSERT INTO sessions (uid, sid, hostname, timestamp) values(%d, '%s', '%s', %d)", $user->uid, session_id(), $_SERVER["REMOTE_ADDR"], time());
+        }
+
+        // also update the user table timestamp noting user has logged in
+        db_query("UPDATE users SET timestamp = '%d' WHERE uid = '%s'", time(), $user->uid);
+      }
 
       /*
       ** If the user wants to be remembered, set the proper cookie such
diff --git a/modules/user/user.module b/modules/user/user.module
index f579fb2ffe8f..c05bec7c52ee 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -22,25 +22,39 @@ function sess_close() {
 
 function sess_read($key) {
   global $user;
-  $user = user_load(array("sid" => $key, "status" => 1));
+
+  $result = db_query_range("SELECT u.*, s.*, r.name AS role FROM {users} u INNER JOIN {role} r ON u.rid = r.rid INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = '". check_query($key) ."' AND u.status < 3", 0, 1);
+  $user = db_fetch_object($result);
 
   return !empty($user->session) ? $user->session : '';
 }
 
 function sess_write($key, $value) {
 
-  db_query("UPDATE {users} SET hostname = '%s', session = '%s', timestamp = %d WHERE sid = '$key'", $_SERVER["REMOTE_ADDR"], $value, time());
+  db_query("UPDATE {sessions} SET hostname = '%s', session = '%s', timestamp = %d WHERE sid = '$key'", $_SERVER["REMOTE_ADDR"], $value, time());
 
   return '';
 }
 
 function sess_destroy($key) {
 
-  db_query("UPDATE {users} SET hostname = '%s', timestamp = %d, sid = '' WHERE sid = '$key'", $_SERVER["REMOTE_ADDR"], time());
+  db_query("DELETE FROM {sessions} WHERE sid = '$key'");
+
 }
 
 function sess_gc($lifetime) {
+
+  /*
+  **  Be sure to adjust 'php_value session.gc_maxlifetime' to a large enough
+  **   value.  For example, if you want user sessions to stay in your database
+  **   for three weeks before deleting them, you need to set gc_maxlifetime
+  **   to '1814400'.  At that value, only after a user doesn't log in after
+  **   three weeks (1814400 seconds) will his/her session be removed.
+  */
+  db_query("DELETE FROM {sessions} WHERE timestamp < %d", time() - $lifetime);
+
   return 1;
+
 }
 
 /*** Common functions ******************************************************/
@@ -313,7 +327,7 @@ function user_fields() {
   }
 
   // Make sure we return the default fields at least
-  return is_array($fields) ? $fields: array("uid", "name", "pass", "mail", "homepage", "mode", "sort", "threshold", "theme", "signature", "timestamp", "hostname", "status", "timezone", "rating", "language", "sid", "init", "session", "data", "rid");
+  return is_array($fields) ? $fields: array("uid", "name", "pass", "mail", "homepage", "mode", "sort", "threshold", "theme", "signature", "timestamp", "status", "timezone", "rating", "language", "init", "data", "rid");
 }
 
 /*** Module hooks **********************************************************/
@@ -618,9 +632,22 @@ function user_login($edit = array(), $msg = "") {
 
       /*
       ** Write session ID to database:
+      **  (TODO: Currently we only save the session if a user is logged in.
+      **   we should also add support for anonymous user sessions.)
       */
 
-      user_save($user, array("sid" => session_id()));
+      if ($user->uid) {
+        // update the user's session if it already exists
+        db_query("UPDATE sessions SET timestamp = '%d' WHERE sid = '%s'", time(), session_id());
+
+        // if no changes, this is a new session to be added
+        if (!db_affected_rows()) {
+          db_query("INSERT INTO sessions (uid, sid, hostname, timestamp) values(%d, '%s', '%s', %d)", $user->uid, session_id(), $_SERVER["REMOTE_ADDR"], time());
+        }
+
+        // also update the user table timestamp noting user has logged in
+        db_query("UPDATE users SET timestamp = '%d' WHERE uid = '%s'", time(), $user->uid);
+      }
 
       /*
       ** If the user wants to be remembered, set the proper cookie such
diff --git a/update.php b/update.php
index a382668e1008..feff9f2e0094 100644
--- a/update.php
+++ b/update.php
@@ -41,7 +41,8 @@
   "2003-06-08" => "update_57",
   "2003-06-08: first update since Drupal 4.2.0 release" => "update_58",
   "2003-08-05" => "update_59",
-  "2003-08-15" => "update_60"
+  "2003-08-15" => "update_60",
+  "2003-08-20" => "update_61"
 );
 
 function update_32() {
@@ -331,6 +332,23 @@ function update_60() {
   update_sql("ALTER TABLE forum DROP icon");
 }
 
+function update_61() {
+  update_sql("CREATE TABLE IF NOT EXISTS sessions (
+    uid int(10) unsigned NOT NULL,
+    sid varchar(32) NOT NULL default '',
+    hostname varchar(128) NOT NULL default '',
+    timestamp int(11) NOT NULL default '0',
+    session text,
+    KEY uid (uid),
+    KEY sid (sid(4)),
+    KEY timestamp (timestamp)
+  )");
+
+  update_sql("ALTER TABLE users DROP session;");
+  update_sql("ALTER TABLE users DROP hostname;");
+  update_sql("ALTER TABLE users DROP sid;");
+}
+
 function _update_next_thread($structure, $parent) {
   do {
     $val++;
-- 
GitLab