Problema APC + attributi statici

Ciao a tutti,

ho un problema del quale non riesco ad individuare la causa. Ho creato una mia classe di gestione delle sessioni tramite db che a sua volta istanzia in modo statico una classe che ho creato per l'accesso al database e che restituisce la connessione verso quest'ultimo.

Sul server mi sono fatto installare APC che posso abilitare o disabilitare con un flag via htaccess.

Fino ad ora ho eseguito le prove del login con APC disabilitato e tutto funziona alla perfezione ma appena l'ho abilitato mi ha mandato in crisi il modulo di gestione delle sessioni.

In particolare il server mi rileva due errori che sono i seguenti:

1) [Tue Sep 13 15:32:29 2011] [error] [client 151.64.206.31] PHP Fatal error: Access to undeclared static property: Manager_DatabaseSessionStorage::$db_connection in /var/www/vhosts/ceramicheria.it/httpdocs/cp/include/manager_databasesessionstorage.php on line 57, referer: http://www.ceramicheria.it/ 

2) [Tue Sep 13 15:33:41 2011] [error] [client 151.64.206.31] PHP Fatal error: Access to undeclared static property: Manager_DatabaseSessionStorage::$db_connection in /var/www/vhosts/ceramicheria.it/httpdocs/cp/include/manager_databasesessionstorage.php on line 74, referer: http://www.ceramicheria.it/

Entrambe gli errori si riferiscono alla classe di gestione della sessione e in particolare suggeriscono che la variabile di sessione non sia dichiarata in modo statico ma io nel codice l'ho dichiarata esattamente in quel modo.

Qualcuno sa dirmi come mai si verifica questo problema quando abilito apc?

Grazie a tutti


Di seguito riporto il codice della classe Manager_DatabaseSessionStorage:

<?
/*----------------------------------------------------------------------
/* Carico le costanti
/*--------------------------------------------------------------------*/
    require_once('constants.php');
/*----------------------------------------------------------------------
/* Carico le librerie di oggetti necessari
/*--------------------------------------------------------------------*/
    require_once('manager_connection.php');
    require_once('manager_rsa.php');
    require_once('manager_security.php');

//-------------------------------------------------------------------------------------------------------
class Manager_DatabaseSessionStorage
{
    private static $db_connection = NULL;
    private $manager_Security;

    // Costruttore della classe alla quale va passata una connessione attuale al database
    function __construct()
    {
        $this->manager_Security = new Manager_Security();

        session_set_save_handler
        (
            array(&$this, 'open'),
            array(&$this, 'close'),
            array(&$this, 'read'),
            array(&$this, 'write'),
            array(&$this, 'destroy'),
            array(&$this, 'gc')
        );
    }

// Distruttore della classe che libera la variabile associata alla connessione al server
    function __destruct()
    {
        unset($this->manager_Security);
    }

    public static function open($save_path, $session_name)
    {
        /* Avvio la connessione al database */
        self::$db_connection = @new mysqli(DataBase_Server, DataBase_UserName, DataBase_Password, DataBase_Name);
        /* Verifico che non ci siano errori durante la connessione */
        if (mysqli_connect_errno() !== 0) {
            return false;
        }
        /* Assicuriamoci che la connessione utilizzi il set di caratteri UTF8 */
        @self::$db_connection->query('SET NAMES \'utf8\'');
    }

    public static function close()
    {
        self::$db_connection->close();
        self::$db_connection = NULL;
    }

    public static function read($id)
    {
        $id = self::$db_connection->real_escape_string($id);
        $result = @self::$db_connection->query("SELECT * FROM SessionData WHERE session_id='$id'");
        if (self::$db_connection->errno != 0) return false;
        $data = '';
        if (($row = @$result->fetch_assoc()) !== NULL) $data = $row['session_data'];
        $result->close();
        return $data;
    }

    public static function write($id, $session_data)
    {
        $id = self::$db_connection->real_escape_string($id);
        $session_data = self::$db_connection->real_escape_string($session_data);
        $result = @self::$db_connection->query("REPLACE INTO SessionData VALUES('$id', NOW(), '$session_data')");
        if (self::$db_connection->errno != 0) return FALSE;
        return TRUE;
    }

    public static function destroy($id)
    {
        $id = self::$db_connection->real_escape_string($id);
        $result = @self::$db_connection->query("DELETE FROM SessionData WHERE session_id='$id'");
        if (self::$db_connection->errno != 0) return FALSE;
        return TRUE;
    }

    public static function gc($maxLifeTime)
    {
        $maxDate = date('Y-m-d H:m:s', time() - $maxLifeTime);
        $result = @self::$db_connection->query("DELETE FROM SessionData WHERE last_update < '$maxDate'");
        if (self::$db_connection->errno != 0) return FALSE;
        return TRUE;
    }

    public function StartSecureSession($in_SessionName, $in_DomainName, $in_MaxLifeTime, $in_LoginAgainPageUrl, $in_HashFunction = constantHashSHA512)
    {
        //  specifica se il modulo di sessione inizia una sessione automaticamente su richiesta iniziale. Di default  0 (disattivata).
        ini_set('session.auto_start', 0);
        // specifica la probabilit , in percentuale ,che la routine gc (garbage collection) sia cominciata ad ogni richiesta in percentuale. Di default  1.
        ini_set('session.gc_probability', 1);
        // definisce la probabilit che sia avviato il processo di garbage collection. La probabilit  calcolata usando
        // gc_probability / gc_divisor. Per esempio 1/100 significa 1% di probabilit
        ini_set('session.gc_divisor', 100);
        // specifica il numero di secondi dopo i quali i dati saranno considerati 'spazzatura' e cancellati.
        ini_set('session.gc_maxlifetime', 60 * 60 * 24);
        // specifica il numero di secondi dopo i quali il cookie di sessione viene eliminato
        ini_set('session.cookie_lifetime', 60 * 60 * 24);
        // contiene la sottostringa con cui volete controllare ogni HTTP referer
        ini_set('session.referer_check', '');
        // addizionale sorgente entropica nella crazione dell'id di sessione
        ini_set('session.entropy_file', '/dev/urandom');
        // specifica il numero di bytes che saranno letti dal file specificato sopra. Di default  0 (disattivato).
        ini_set('session.entropy_length', 512);
        // specifica se il modulo user i cookies per archiviare l'id di sessione sul lato client. Di default  1 (attivo).
        ini_set('session.use_cookies', 1);
        // specifica se il modulo potr usare esclusivamente o meno i cookies per immagazzinare l'id di sessione lato client.
        // impostato su 1 il modulo potr usare solo i coookie
        ini_set('session.use_only_cookies', 1);
        // specifica se il supporto sid trasparente  attivato o no se attivato compilandolo con --enable-trans-sid. Di default  1 (attivo).
        ini_set('session.use_trans_sid', 0);
        // specifica l'algoritmo di hash usato per generare l'id di sessione. In questo caso
        ini_set('session.hash_function', $in_HashFunction);
        // definisce quanti bits sono immagazzinati per ogni carattere per convertire i dati binari in qualcosa di leggibile
        // impostando il valore a 6 i valori possibili sono "0-9", "a-z", "A-Z", "-", ","
        ini_set('session.hash_bits_per_character', 5);

        // Imposto il caching della pagina su "nocache":
        // dice a qualsiasi dispositivo di nn fare caching del contenuto,
        // ma permette quello di css e risorse esterne come le immagini
        session_cache_limiter("nocache");

        // imposta il tempo massimo di vita dei cookie definito in secondi, la path sul dominio (usando '/' viene accettato qualsiasi percorso sul dominio)
        // e imposta i cookies solo per i domini e sottodomini specificati
        session_set_cookie_params(60 * 60 * 24, '/', '.' . strtolower($in_DomainName));

        // Imposto un nome di sessione
        session_name($in_SessionName);

        // avvio la sessione
        session_start();

        // PREVENIRE => S
inviato 5 anni fa
elaidon
modificato 5 anni fa
Gianni Tomasicchio
Puoi modificare la domanda formattando il codice dal menu "Formato"->"Formattato" e non con il pulsante "Citazione"?Gianni Tomasicchio 5 anni fa
X 1 X

Sembra che questo sia un comportamento noto di APC che effettua una "pulizia" degli attributi statici delle classi al termine dell'esecuzione:

http://pecl.php.net/bugs/bug.php?id=21218

Tieni presente che, se non espressamente invocata con session_write_close(), la chiusura della sessione e l'invocazione dei metodi write e close avviene dopo l'esecuzione del tuo script. Fuori tempo massimo per APC che ha gią iniziato a fare le pulizie...

Due le soluzioni consigliate:

  1. Invertire l'ordine di caricamento delle estensioni, mettendo prima session e poi APC.
  2. Terminare l'esecuzione dello script con una chiamata esplicita alla funzione session_write_close().
risposto 5 anni fa
Gianni Tomasicchio
Ciao Gianni, grazie per le indicazioni. Mi sfugge però cosa intendi al punto 1 per invertire l'ordine di caricamento delle estensioni. Intendi invertire l'ordine di caricamento dei moduli sul server, cioè cambiare la configurazione del server?elaidon 5 anni fa
@elaidon Si, mi riferisco all'ordine con cui vengono caricate le estensioni, specificato nel php.ini del server.Gianni Tomasicchio 5 anni fa
@Gianni Tomasicchio, grazie per i suggerimenti. Ho chiesto a chi mi gestisce il server di controllare l'ordine di caricamento delle estensioni e di assicurarsi che session sia caricata prima di apc. Verdiamo un pò che succede. Grazieelaidon 5 anni fa
Novità? Ha funzionato?Gianni Tomasicchio 5 anni fa
ho aggiunto session_write_close() nel __descrut di Manager_DatabaseSessionStorage e funziona. Ho anche aggiornato all'ultima versione stabile di APC. Avevo la 3.0.19 e mi hanno messo la 3.1.9 ma ora ho dei problemi su due domini e sto chiedendo il downgrade perchè con i siti fermi mi spellano vivo :)elaidon 5 anni fa
X 0 X X
Effettua l'accesso o registrati per rispondere a questa domanda