Ankündigung

Einklappen
Keine Ankündigung bisher.

Memcached SessionHandlerInterface max 1 Session :(

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Memcached SessionHandlerInterface max 1 Session :(

    Hallo,

    ich musste gerade feststellen das der SessionHandler irgendwie nur maximal 1 Session speichert.
    Habe die Seite in 2 verschiedene Browser auf (jeweils mit nem anderen User eingeloggt) und sobald der eine Browser die Seite neu geladen hat, ist die andere Sitzung aus Memcached raus.

    PHP-Code:
    // Initzialisierung der Session

            
    header('x-xss-protection: 1; mode=block');
            
    header('x-content-type-options: nosniff');
            
    header('x-frame-options: SAMEORIGIN');

            
    header('Cache-Control: public, max-age=31536000');
            
    // Session Settings
            
    ini_set('session.use_cookies'true); // Cookies are safer
            
    ini_set('session.cookie_domain'self::$domain);
            
    ini_set('session.use_only_cookies'true); // not all user allow cookies
            
    ini_set('session.cookie_secure'true); // only on https will cookies be send
            
    ini_set('session.cookie_httponly'true); // JS can not acces to session-Cookie
            // ini_set("session.hash_function",  "1"); // removed on PHP 7.1.0
            
    ini_set('session.sid_length'22); // PHP 7.1.0 >
            
    ini_set('session.sid_bits_per_character'6);
            
    ini_set('session.cookie_lifetime''0'); // Cookie-Lebensdauer, '0' = "bis der Browser geschlossen wird
            
    ini_set('session.gc_maxlifetime'10800); // Ab wann Sessions als 'garbage' ('Müll') betrachtet und ggf. entsorgt werden könnten
            // ini_set('session.gc_probability', 1);
            // ini_set('session.gc_divisor', 1);

            
    session_cache_limiter('nocache');
            
    session_name('ws'); // Don`t change !!!
            
    switch( $sessMode ){ // the key contains the mode
                
    case 'memcache':
                case 
    'memcached':
                    
    session_set_save_handler(new memSess($sessMode$serversarray_shift($settings)), true); // initalisiert den Handler
                    
    break;
                case 
    'files':
                    new 
    fileSess();
                    break;
                default:
                    
    // All other use default php session - don`t use a interface
                    // ini_set('session.gc_maxlifetime', self::$lifeTime);
            
    }
            
    session_start();
            
    eHandler::datas('sess'$_SESSION); 
    Die entsprechende Klasse
    PHP-Code:
    class memSess implements SessionHandlerInterface{
        private 
    $memcache null;
        private 
    $mode;
        private 
    $quitFunc;
        private 
    $pref;
        private 
    $reedCheck;

        public function 
    __construct($mode$servers$pref){
            
    // eHandler::datas('memSess', [$mode, session::$lifeTime]);
            // register_shutdown_function('session_write_close');

            
    $this->mode $mode;
            
    $this->pref $pref;
            
    $this->memcache = new $mode;

            if( 
    $mode == 'memcached' ){
                
    $this->reedCheck null// memcached return null on not found keys
                
    $this->quitFunc 'quit'// memcached use quit()
                
    $this->memcache->addServers($servers);
            }else{
                
    $this->reedCheck false// memcache return false on not found keys
                
    $this->quitFunc 'close'// memcache use close()
                
    foreach( $servers as $server ){ if( count($server) == ){ self::$cacheInstance->addServer($server[0], $server[1]); }else{ self::$cacheInstance->addServer($server[0], $server[1], $server[2]); } }
            }
        }

        
    /**
         * Destructor
         */
        
    public function __destruct(){
            
    $this->memcache->{$this->quitFunc}();
        }

        
    /**
         * Open the session handler, set the lifetime at session.gc_maxlifetime
         * @return boolean True if everything succeed
         */
        
    public function open($save_path$session_name){
            return 
    true;
        }

        
    /**
         * Read the id
         * @param string $id The SESSID to search for
         * @return string The session saved previously
         */
        
    public function read_err($id){
            
    $_SESSION json_decode($this->memcache->get($this->pref.$id), true);
            
    // if($_SESSION === $this->reedCheck){ $_SESSION = []; }
            
    return '';
        }
        public function 
    read($id){
            
    $tmp $_SESSION;
            
    $_SESSION json_decode($this->memcache->get($this->pref.$id), true);
            if( !empty(
    $_SESSION) && $_SESSION != null ){
                
    $new_data session_encode();
                
    $_SESSION $tmp;
                return 
    $new_data;
            }else{
                return 
    '';
            }
        }

        
    /**
         * Write the session data, convert to json before storing
         * @param string $id The SESSID to save
         * @param string $data The data to store, already serialized by PHP
         * @return boolean True if memcached was able to write the session data
         */
        
    public function write($id$data){
            
    $tmp $_SESSION;
            
    session_decode($data);
            
    $new_data $_SESSION;
            
    $_SESSION $tmp;
            return 
    $this->{'write'.ucfirst($this->mode)}($id$new_data);
        }

        private function 
    writeMemcache($id$new_data){ return $this->memcache->set($this->pref.$idjson_encode($new_data), 0session::$lifeTime); }
        private function 
    writeMemcached($id$new_data){ return $this->memcache->set($this->pref.$idjson_encode($new_data), session::$lifeTime); }

        
    /**
         * Delete object in session. memache and memcached both the same function
         * @param string $id The SESSID to delete
         * @return boolean True if memcached was able delete session data
         */
        
    public function destroy($id){
            return ( 
    $this->memcache->get($this->pref.$id) === false ) ? true $this->memcache->delete($this->pref.$id0);
        }

        
    /**
         * Close gc
         * @return boolean Always true
         */
        
    public function gc($maxlifetime){
            return 
    true;
        }

        
    /**
         * Close session, quit for memcached
         * @return boolean Always true
         */
        
    public function close(){
            return ( 
    $this->mode == 'memcached' ) ? $this->memcache->quit() : true;
        }

    Ich habe jetzt schon einige Tests gemacht aber ich komme dem Fehler nicht auf die Spur
    Aber da oben in der switch()-Anweisung mit new memSess() der Handler ja initialisiert und gesetzt wird und in der nächsten Zeile wird die Session erstellt und gleich darauf ist die Session dann leer. Also kann es doch garnicht anders sein als das die vorherige Session schlicht und ergreifend überschrieben wird (und somit immer die zuletzt genutzte vorhanden ist).

    Ein Test in WebSocket legt dies auch nahe, denn dort wird beim verbinden die Session aus Memcache geladen und validiert und hier bekomme ich ebenfalls die Meldung das diese nicht existiert.
    Nun ist die Frage wo der Fehler ist, denn die write()-Funktion funktioniert ja sonst würde es bei jedem Laden/connect eine leere Sitzung geben, dies ist aber ja nur der Fall wenn eine andere session_ID die Seite lädt (kickt die alte raus).

    Ich hoffe Jemand hat damit schon mal Erfahrung gemacht und kann mir weiterhelfen!

    LG: Paykoman

  • #2
    Warum pfuscht der Session-Handler in der $_SESSION-Variable herum? Das geht ihn nichts an und führt zu unerwünschten Seiteneffekten.

    Kommentar


    • #3
      Hmm gute Frage
      Ich habe aber auch fix ein wenig gegoogelt und die ganze Klasse noch mal überarbeitet...

      PHP-Code:
      class MemcachedSessionHandler implements SessionHandlerInterface{
          private 
      $memcached;
          private 
      $ttl;
          private 
      $prefix;

          
      /**
           * Constructor.
           *
           * List of available options:
           *  * prefix: The prefix to use for the memcached keys in order to avoid collision
           *  * expiretime: The time to live in seconds
           *
           * @param Memcached  $memcached A Memcached instance
           * @param array      $options   An associative array of Memcached options
           *
           * @throws \InvalidArgumentException When unsupported options are passed
           */
           
      public function __construct($mode$servers$pref){
              
      // eHandler::datas('memSess', [$mode, session::$lifeTime]);
              // register_shutdown_function('session_write_close');

              
      $this->ttl session::$lifeTime;
              
      $this->prefix $pref;
              
      $this->memcached = new Memcached;
              
      $this->memcached->addServers($servers);
          }

          public function 
      _constructMemcached $memcached, array $options = array() ){
              
      $this->memcached $memcached;
              if ( 
      $diff array_diffarray_keys$options ), array( 'prefix''expiretime' ) ) ) {
                  throw new \
      InvalidArgumentExceptionsprintf(
                      
      'The following options are not supported "%s"',
                      
      implode', '$diff )
                  ) );
              }
              
      $this->ttl    = isset( $options'expiretime' ] ) ? (int)$options'expiretime' ] : 86400;
              
      $this->prefix = isset( $options'prefix' ] ) ? $options'prefix' ] : 'sf2s-';
          }

          public function 
      open$savePath$sessionName )
          {
              return 
      true;
          }

          public function 
      close(){
              return 
      true;
          }

          public function 
      read$sessionId ){
              return 
      $this->memcached->get$this->prefix $sessionId ) ? : '';
          }

          public function 
      write$sessionId$data ){
              return 
      $this->memcached->set$this->prefix $sessionId$datatime() + $this->ttl );
          }

          public function 
      destroy$sessionId ){
              return 
      $this->memcached->delete$this->prefix $sessionId );
          }

          public function 
      gc$lifetime ){
              
      // not required here because memcached will auto expire the records anyhow.
              
      return true;
          }

      Aber bringt nichts, es bleibt bei dem Problem das maximal eine Sitzung gespeichert wird, bzw. die vorhandene überschrieben wird
      Ich will noch mal fix testen ob es an meinem CMS liegt, aber ich denke nicht denn direkt nach session_start(); ist die session leer daher kann es eig. nur an Memcached liegen

      ::EDIT::
      hmm, muss wohl doch am CMS liegen, habe jetzt mal alles in die index.php gepackt und dort funktioniert es.
      Find das über aus komisch aber gut dann mal auf zur Fehlersuche

      Kommentar


      • #4
        Du hast oben zwei __construct(){] ist das wichtig ?

        Kommentar


        • #5
          Moin moin,

          mit frischer Energie habe ich das Problem gefunden.
          Da viele Grundsysteme noch ausführlich debugged werden, habe ich am Anfang meines scripts ein cache::flush(), dieser interne cache speichert Daten ebenfalls via Memcached.
          Obwohl beide eine eigene memcached Instanz verfügen, löscht es die Sessions gleich mit *rofl*

          Nun bin ich über diese Option gestoßen:
          Code:
          self::$cacheInstance->setOption(Memcached::OPT_PREFIX_KEY, 'c/');
          Das selbe habe ich der Session verpasst mit 'sess/' aber scheint das Problem nicht zu lösen.
          Hatte gehofft das mit prefixe, die jeweiligen Serververbindungen sich eben auf diese reduzieren und nicht mehr auf alles was in memcached vorhanden ist.

          Gibt es da eine Lösung ohne das der cache alle keys einzelnd löschen muss?

          LG: Paykoman

          Kommentar

          Lädt...
          X