fatto l'esame
si', cmq, uso due cookie e un database. ti posto il codice come appare attualmente. dovrei pulirlo un po' che fa un po' schifo, ma rende l'idea di cio' che ho fatto 
è troppo lungo per incollarlo per intero (la mia classe ha anche alcuni metodi per login e logout, per le variabili di sessione ecc.), ti posto invece i due metodi che sono il "nocciolo" della mia soluzione...spero sia ugualmente comprensibile.
La mia classe Session presenta questo costruttore:
codice:
public function __construct(){
$db = SamarcandaGlobalContainer::getDatabaseConnection();
$this->_table_prefix = "samarcanda_";
$this->_table_utenti = $this->_table_prefix . "utenti";
$this->_table_categorie = $this->_table_prefix . "categorie";
// Cancella le sessioni e le variabili troppo vecchie
$db->query("DELETE FROM " . $this->_table_prefix . "session WHERE (((last_impression + INTERVAL 10 MINUTE) < NOW()) OR ((when_created + INTERVAL 2 HOUR) < NOW()))");
$db->query("DELETE FROM " . $this->_table_prefix . "session_vars WHERE ((last_impression + INTERVAL 10 MINUTE) < NOW())");
$t_session = SamarcandaGlobalContainer::getHTTPParameter("samarcanda2primarysessid");
$t_secondary = SamarcandaGlobalContainer::getHTTPParameter("samarcanda2secondarysessid");
// Se non esiste nessuna sessione ne crea una non autenticata
if(!($t_secondary)){
$this->newSession();
$this->_logged_in = 0;
$this->_userid = 2;
}
// Se la sessione esiste ne carica i dettagli dal database
else {
$ip_separato = array();
$ip_separato = split("\.", $_SERVER['REMOTE_ADDR']);
$mezzo_ip = join(".", array($ip_separato[0], $ip_separato[1]));
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$timeout = $this->_timeout_value;
$max_time = $this->_max_session_age;
$sql = "SELECT id, logged_in, user_id FROM " . $this->_table_prefix . "session WHERE session_id = '" . $t_session . "' AND secondary_key = '" . $t_secondary . "' AND user_agent = '" . $user_agent . "' AND ip_address = '" . $mezzo_ip . "'";
//$sql = "SELECT id, logged_in, user_id FROM " . $this->_table_prefix . "session WHERE session_id = '" . $t_session . "' AND secondary_key = '" . $t_secondary . "' AND (NOW() - when_created <= " . $max_time . ") AND user_agent = '" . $user_agent . "' AND ip_address = '" . $mezzo_ip . "'";
$res = $db->query($sql);
// Se la sessione e' invalida per qualche motivo ne crea una nuova
if(!($res->num_rows)) {$this->_userid = 2; $this->_logged_in = 0; $this->newSession(); }
else {
$row = $res->fetch_assoc();
// Aggiorna le variabili di classe
$this->_sessionID = $t_session;
$this->_secondary_key = $t_secondary;
$this->_userid = $row["user_id"];
$this->_logged_in = $row["logged_in"];
// Aggiorna, per la sessione corrente, con un valore aggiornato di tempo per last_impression
$db->query("UPDATE " . $this->_table_prefix . "session SET last_impression = NOW() WHERE id = '" . $row["id"] . "'");
}//Endif:valid session
}//Endif::session exist
}
come vedi uso un primarysessionid e un secondarysessionid per maggiore sicurezza
ma l'incasinamento piu' grande e' nel metodo newSession...
codice:
public function newSession(){
$db = SamarcandaGlobalContainer::getDatabaseConnection();
$t_primario = SamarcandaGlobalContainer::getHTTPParameter("samarcanda2primarysessid");
$t_secondario = SamarcandaGlobalContainer::getHTTPParameter("samarcanda2secondarysessid");
// Controlla se esiste gia' una sessione con questi dati. Nel caso esista, la cancella dal database
// prima di sostituirla con una nuova
if(($t_primario) && ($t_secondario)){
// cancellazione della sessione corrente dalla tabella delle sessioni
$db->query("DELETE FROM " . $this->_table_prefix . "session WHERE session_id = '" . $t_primario . "'");
// cancellazione di tutte le variabili associate alla sessione appena cancellata
$db->query("DELETE FROM " . $this->_table_prefix . "session_vars WHERE session_id = '" . $t_primario . "'");
}
// Creazione di una nuova sessione
// La session_id e' una combinazione criptata della user_agent, della tavola dei processi attivi, dei primi due ottetti dell'indirizzo
// IP remoto e della timestamp corrente. E' praticamente IMPOSSIBILE individuarla tramite bruteforce :)
$ip_separato = array();
$ip_separato = split("\.", $_SERVER['REMOTE_ADDR']);
$mezzo_ip = join(".", array($ip_separato[0], $ip_separato[1]));
$timestamp = mktime();
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$sess_to_md5 = $mezzo_ip . $timestamp . $user_agent . `ps axuw`;
$nuova_sessid = md5($sess_to_md5);
$this->_sessionID = $nuova_sessid;
// Creazione ed invio del cookie primario
setcookie("samarcanda2primarysessid", $nuova_sessid, mktime() + 128800, "/");
// Creazione della chiave di autenticazione secondaria
// E' una combinazione della tavola dei processi e della microtimestamp
$nuova_sec_key = md5(`ps axuw` . microtime());
// Creazione del cookie secondario
setcookie("samarcanda2secondarysessid", $nuova_sec_key, mktime() + 128800, "/");
// Infine aggiungiamo le informazioni sulla sessione alla tabella delle sessioni
$db->query("INSERT INTO " . $this->_table_prefix . "session (session_id, ip_address, user_agent, logged_in, last_impression, when_created, secondary_key) VALUES ('" . $nuova_sessid . "', '" . $mezzo_ip . "', '" . $user_agent . "', 0, NOW(), NOW(), '" . $nuova_sec_key . "')");
return true;
}
tanto codice e poca spiegazione, lo so, ma nn ho ancora avuto il tempo di farmi il bel "pacchetto classe" da distribuire ai benzinai 
se ti serve aiuto per la comprensione, fammi un fischio!