Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] Identyfikator sesji, Session Handler
Forum PHP.pl > Forum > Przedszkole
gosc
Witam,
Napisałem swojego Session Handlera, wszystko działa, tylko jest mały szczegół. PHP nie generuje mi zawsze 32-znakowego identyfikatora sesji, tylko krótszy, np. 26-znakowy, 28-znakowy - różnie, jednak za każdym razem inaczej. Czy PHP powinien domyślnie generować tylko 32-znakowe identyfikatory, czy założenie twórców języka jest, że ma to być ciąg do 32 znaków? A może mam coś żle ustawione w php.ini?

Druga sprawa, to problem wykorzystanie Uchwytu Sesji w pewnym fragmencie kodu. Otóż mam klasę odpowiedzialną za generowania 5-znakowych stringów i wstawianie ich do pliku graficznego, czyli pospolity token. Problem rozwiązuje w ten sposób, że utworzyłem plik token.php, a w nim instancję klasy Token wraz z metodą wyświetlająca obrazek. Do tego pliku odwołuję się w pliku register.tpl (używam systemu szablonów Smarty) i po prostu wstawiam do niego odwołanie w znacznikach <img>. Obrazek wyświetla się poprawnie. Mój problem polega jednak na tym, że w pliku token.class.php nie mogę powtórnie (bo pierwszy raz jest to zrobione register.php) uruchomić sesji przez klasę do obsługi sesji. Wtedy dostaję informację, że albo obrazek zawiera błędy, albo nie jest on generowany. Muszę jednak zrobić jakoś wywołać sesję bo nie widzę innego sposobu, aby zachować wygenerowany string tokenowy pomiędzy odświeżeniami. Jak rozwiązać ten problem?
erix
Cytat
Muszę jednak zrobić jakoś wywołać sesję bo nie widzę innego sposobu, aby zachować wygenerowany string tokenowy pomiędzy odświeżeniami.

W URL-u jakiś parametr typu request id i przechowywać dane w sesji, np.
  1. <?php
  2. $_SESSION['request']['identyfikator'] = 'wartosc tokena';
  3. ?>

które po użyciu kasujesz.

Cytat
PHP nie generuje mi zawsze 32-znakowego identyfikatora sesji, tylko krótszy, np. 26-znakowy, 28-znakowy - różnie, jednak za każdym razem inaczej

W manualu masz coś takiego:
Cytat
session.hash_function integer
session.hash_function allows you to specify the hash algorithm used to generate the session IDs. '0' means MD5 (128 bits) and '1' means SHA-1 (160 bits).


W komentarzach:
Cytat
You may for example set it to 1 to switch to SHA-1 which produces 160 bits (20 bytes) long hashes.
Please also note that another setting was introduced in PHP 5 (session.hash_bits_per_character) which sort of "compresses" the hash. Thus, resulting in what seems to be a shorter hash.
-gość-
Kod
W URL-u jakiś parametr typu request id i przechowywać dane w sesji, np.


Nie bardzo wiem, czy Pan zrozumiał mój problem. Żeby dodać jakąkolwiek wartość do zmiennej sesyjnej, muszę wywołać funkcję session_start(), która u mnie znajduje się w klasie Session. Jednak wywołanie session_start() w klasie równolegle w innym miejscu w skrypcie, gdy jest już wywołana, powoduje powstawanie błędów - obrazek się nie generuje.

Wygląda to tak:

Mam pliki:

register.php - i w nim tworzę egzemplarz klasy Session.

token.php - tu tworzę egzemplarz klasy Token, która niejawnie musi też korzystać z Session.

Jednak wywołanie klasy Session dwa razy prowadzi do komplikacji o których napisałem.
erix
Cytat
Nie bardzo wiem, czy Pan zrozumiał mój problem.

Nie mów per pan, jeszcze jestem na to za młody. ;p

Cytat
Jednak wywołanie session_start() w klasie równolegle w innym miejscu w skrypcie, gdy jest już wywołana, powoduje powstawanie błędów

Tak być nie powinno, rzuć jakiś kod.
m44
Witam,
Wczorajszym autorem wpisu jestem ja. Zamieszczam zatem kod który powoduje komplikacje w postaci nie wyświatlania obrazków, gdy tworzę równolegle egzemplarz klasy Session w klasie Token:

Klasa Token:

Kod
      
        <?php
        
        require_once ('class/StringGenerator.class.php');
    require_once ('class/Session.class.php');
        
        
        
        class Token
        {
        
            private $objStringGenerator;
            private $strLength = 5;
            private $sizeW = 150;
            private $sizeY = 70;
            private $imgResource;
            private $fontColor;
            private $fontDir = 'token/token.ttf';
            private $fontSize = 30;
            private $returnImage;
            private $objSession;
        
            public function __construct()
            {
                $this->objStringGenerator = StringGenerator::GetString($this->strLength);
            $this->objSession = new Session(); //jesli jest dodany zakomentowany fragment, obrazki sie nie wyswietlaja, czyli juz od momentu tworzenia nowej instancji klasy
         // w tym samym czasie z klasy sesji korzysta też register.php
            $_SESSION['token'] = $this->objStringGenerator; //cd.
            }
            
            private function CreateImage()
            {
                return imagecreatetruecolor($this->sizeW, $this->sizeY);
            }
        
            public function GetString()
            {
                return $this->objStringGenerator;    
            }
        
            public function Execute()
            {
                $this->imgResource = $this->CreateImage();
                $this->ImageFillColor();
                $this->Imagettftext();
                $this->returnImage = imagejpeg($this->imgResource);
                imagedestroy($this->imgResource);
                return $this->returnImage;
            }
        
            private function SetFontColour()
            {
                return imagecolorallocate($this->imgResource, 0, 0, 0);
            }
            
            private function Imagettftext()
            {
                return imagettftext($this->imgResource, $this->fontSize, rand(-5, 5), 5, 50, $this->SetFontColour(), $this->SetFont(), $this->objStringGenerator);
            }
        
            private function SetFont()
            {
                return $this->fontDir;
            }
        
            private function ImageFillColor()
            {
                return imagefilledrectangle($this->imgResource, 0, 0, 400, 70, $this->WhiteColor());
            }
        
            private function WhiteColor()
            {
                return imagecolorallocate($this->imgResource, 255, 255, 255);
            }
        }
        
        ?>


Plik token.php:

Kod
  
    <?php
    //Wczytanie generatora obrazków
    require_once ('class/Token.class.php');
    
    $token = new Token();
    $token->Execute();
    ?>


Odwołanie do token.php znajduje się w szablonach Smarty w <img>. Może teraz widać gdzie robię błąd?
erix
A klasa Session co zawiera? Wspomniałeś wcześniej o jakichś błędach, co to za błędy?
m44
Właściwie błędów jako takich nie ma, tylko w przypadku powtórnego użycia obiektu obrazek się nie generuje (wyświetla się sam tekst z tagu "alt"). Daję zatem klasę Session (dzielę wpis na 2 cześci bo w jednym się nie zmieści):
Kod

require_once ('class/MySQL.class.php');
require_once ('class/Browser.class.php');
require_once ('class/CountSQL.class.php');

class Session
{

    private $objSql;
    private $objBrowser;
    
    private $session_name = 'sid';
    private $session_id;
    private $native_session_id;
    private $db_prefix;
    private $ip;
    private $browser_name;
    private $session_lifespan = 3600;
    private $session_timeout = 600;
    private $session_value;
    
    private $timestamp;
    private $zero = 0;
    private $null_session_varible = '';

    public function __construct()
    {
        $this->objSql = MySQL::connect();
        $this->objBrowser = new Browser();
        
        
        $this->db_prefix = MySQL::$db_prefix;
        $this->browser_name = $this->objBrowser->GetBrowserName();
        $this->ip = $_SERVER["REMOTE_ADDR"];
        $this->timestamp = time();
        
        session_set_save_handler(
        array(&$this, 'session_open'),
        array(&$this, 'session_close'),
        array(&$this, 'session_read'),
        array(&$this, 'session_write'),
        array(&$this, 'session_destroy'),
        array(&$this, 'session_gc')
        );
        
        if(isset($_COOKIE[$this->session_name]))
        {
            $this->session_id = $_COOKIE[$this->session_name];
            $stmt = $this->objSql->stmt_init();
            $stmt->prepare("SELECT * FROM ".$this->db_prefix."sessions WHERE sessions_identifer =? AND sessions_useragent =? AND sessions_ip =? AND (sessions_start + ?) > UNIX_TIMESTAMP() AND (    sessions_last_time + ?) > UNIX_TIMESTAMP()");
            $stmt->bind_param("sssii", $this->session_id, $this->browser_name, $this->ip, $this->session_lifespan, $this->session_timeout);
            $stmt->execute();
            CountSQL::AddSQL();
            $stmt->store_result();
            $rows = $stmt->num_rows;
            
            
            if($rows==0)
            {
                if($this->ValidateSessionId())
                {
                    $bool = setcookie($this->session_name, $this->session_id, time() -3600);
                    unset($_COOKIE[$this->session_name]);
                }
                $this->DeleteOldSessions();
            }
            else
            {
                $this->Impress();
            }
            


        }
        session_set_cookie_params($session_lifespan=0);
        session_start();    
        
    }
    
    public function session_open($session_savepath, $session_name)
    {                    
            return(true);        
    }
    
    public function session_close()
    {
        $this->session_gc();
        $this->objSql->close();
        return(true);    
    }
    
    public function session_read($session_id)
    {
        if(isset($_COOKIE[$this->session_name]))
        {
            $stmt = $this->objSql->stmt_init();
            $stmt->prepare("INSERT INTO ".$this->db_prefix."sessions VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
            $stmt->bind_param("issiissi", $this->zero, $this->session_id, $this->null_session_varible, $this->timestamp, $this->timestamp, $this->ip, $this->browser_name, $this->zero);
            $stmt->execute();
            CountSQL::AddSQL();
            
        
            $sql = "SELECT sessions_varible FROM ".$this->db_prefix."sessions WHERE sessions_identifer = '$this->session_id'";
            $query = $this->objSql->query($sql);
            CountSQL::AddSQL();
            while($value = $query->fetch_assoc())
            {
                $return = $value['sessions_varible'];                    
            }
            
            return $return;
            }
        
            
    }
    
    public function session_write($session_id, $session_value)
    {
        if(isset($_COOKIE[$this->session_name]))
        {
            $stmt = $this->objSql->stmt_init();
            $stmt->prepare("UPDATE ".$this->db_prefix."sessions SET sessions_varible =? WHERE sessions_identifer =?");
            $stmt->bind_param("ss", $session_value, $session_id);
            $stmt->execute();
            CountSQL::AddSQL();
        return(true);
        }    
    }
     [cdn :-)]


Kod
public function session_destroy($session_id)
    {
        $stmt = $this->objSql->stmt_init();
        $stmt->prepare("DELETE FROM ".$this->db_prefix."sessions WHERE sessions_identifer =?");
        $stmt->bind_param("s", $session_id);
        $stmt->execute();
        CountSQL::AddSQL();
        return(true);    
    }
    
    public function session_gc()
    {
        $stmt = $this->objSql->stmt_init();
        $stmt->prepare("DELETE FROM ".$this->db_prefix."sessions WHERE  (sessions_last_time + ?) < UNIX_TIMESTAMP()");
        $stmt->bind_param("s", $this->session_timeout);
        $stmt->execute();
        CountSQL::AddSQL();
        return(true);    
    }
    
    private function ValidateSessionId()
    {
        if(!ereg("[a-z0-9]{32}", $this->session_id))
        return(true);    
    }
    
    private function Impress()
    {
        $stmt = $this->objSql->stmt_init();
        $stmt->prepare("UPDATE ".$this->db_prefix."sessions SET sessions_last_time = UNIX_TIMESTAMP() WHERE sessions_identifer =? AND sessions_ip =? AND sessions_useragent =?");    
        $stmt->bind_param("sss", $this->session_id, $this->ip, $this->browser_name);
        $stmt->execute();
        CountSQL::AddSQL();        
    }
    
    private function DeleteOldSessions()
    {
        $stmt = $this->objSql->stmt_init();
        $stmt->prepare("DELETE FROM ".$this->db_prefix."sessions WHERE sessions_identifer =? OR (sessions_start + ?) < UNIX_TIMESTAMP()");
        $stmt->bind_param("si", $this->session_id, $this->session_lifespan);
        $stmt->execute();
        CountSQL::AddSQL();        
    }
    
    
    
}


?>
erix
Cytat
Właściwie błędów jako takich nie ma

A error_reporting włączone?

Nie wiem, co generuje ta Twoja klasa StringGenerator, ale sprawdź, czy faktycznie zwraca Ci ten ciąg, którego potrzebujesz i czy w sesji są trzymane jakieś dane.

PS. dobrze by było, gdybyś nie nazywał swoich funkcji tak, jak te z PHP; z początku myślałem, że to funkcja z rdzenia, a nie Twoja. ;p Myślę, że nie tylko ja tak pomyślałem. winksmiley.jpg
megawebmaster
A może by wrzucić tworzenie tylko wskaźnika do obiektu? Mianowicie
Kod
$session = &new Session;

Albo zaimplementowanie wzorca singleton do klasy sesji i pobieranie instancji - ja zrozumiałem błąd, że drugi raz utworzona sesja wywala błąd, więc może tutaj jest problem?
erix
Cytat
ja zrozumiałem błąd, że drugi raz utworzona sesja wywala błąd, więc może tutaj jest problem?

Ale to są osobno działające skrypty, nie dzielą instancji między siebie. winksmiley.jpg
megawebmaster
Więc dlaczego powstaje problem w wyniku 2-krotnego użycia sesji? A może jednak zależą od siebie (przekazanie tokenu przez sesję)?
erix
Dlaczego? Bo mogą mieć różne identyfikatory i wtedy jeden skrypt nie może skorzystać z danych drugiego, ponieważ wskazują na inne puszki ze studencką. winksmiley.jpg
megawebmaster
No to właśnie dlatego skorzystać z jednej instacji wypadałoby winksmiley.jpg I od razu mamy jeden identyfikator sesji i jedną sesję, która (chyba) ma służyć do rejestrowania użytkowników.
erix
Ale identyfikator sesji ma się nijak do instancji klas...

Dobra, koniec offtopa, bo się jeszcze góra przyczepi. tongue.gif
m44
Witam,
Od początku. Klasy StringGenerator używam także w innych miejscach i skryptach więc działa ona prawidłowo. Na pewno nie jest to problem tworzenia ponownego sesji. Sprawdzałem już wcześniej za pomocą flagi (domyślnie pustej), a zmieniającej wartość tylko wtedy, kiedy tworzona jest instancja - jeśli została już utworzona, nie robi tego drugi raz (to chyba Singleton?). I nic. Dzisiaj zmodyfikowałem nawet skrypt, żeby można było pominąć na chwile tworzenie egzemplarza klasy sesji w pliku wczytywanym obok - register.php, i problem występuje dalej i polega on tylko na tym, że obrazek nie jest generowany, wszystko inne, czyli zapisanie ciacha sesyjnego, rozpoczęcie sesji działa, tylko obrazek się nie wyświetla. Wydaje mi się że konflikt polega na równoczesnym korzystaniu z biblioteki GD w klasie Token, ktora powinna wykonywać czynności związana stricte z obróbka grafiki. Jakiekolwiek wstawienie tam innych operacji prowadzi do komplikacji o których mowa. Zresztą kiedy wywoływana jest metoda execute klasy Token, dane sesyjne nie zapisują się w bazie. Kiedy zakomentuję tę metodę i wywołam sesje z Handlera + zapisze wygenerowany string w $_SESSION, to pojawia się on w bazie. Czyli problem jest z wykonywaniem pewnych prostych procesów graficznych i operacji typu sesja równocześnie.
megawebmaster
Erix - no tak tutaj masz rację... Chociaż dla mnie i tak w momencie przechowywania identyfikatora w obiekcie sesji (jak ma to tutaj miejsce) oznacza wykorzystanie tego samego.

m44 - sprawdzałeś może czy wykonanie tylko execute() z klasy Token działa?

EDIT: Oczywiście wywołując tworząc tylko obiekt klasy Token i sprawdzając smile.gif Może gdzieś w nim samym jest błąd, którego nie bardzo widać...
m44
Cytat(megawebmaster @ 18.11.2008, 21:33:15 ) *
Erix - no tak tutaj masz rację... Chociaż dla mnie i tak w momencie przechowywania identyfikatora w obiekcie sesji (jak ma to tutaj miejsce) oznacza wykorzystanie tego samego.

m44 - sprawdzałeś może czy wykonanie tylko execute() z klasy Token działa?

EDIT: Oczywiście wywołując tworząc tylko obiekt klasy Token i sprawdzając smile.gif Może gdzieś w nim samym jest błąd, którego nie bardzo widać...


Raz z sesją, raz bez sesji czyli samo Execute - w ostatnim przypadku działa, bo obrazki się generują, więc klasa raczej jest ok. Utworzenie obiektu token w innych miejscach w skrypcie też działa, tylko z powodu nagłówkow wyświetla ten bajzel od gd na początku. Widac więc że sama klasa Token jest ok.
megawebmaster
Próbowałeś mimo wszystko z tą jedną instancją sesji? No bo inaczej to nie mam pojęcia do czego tu się podpiąć, skoro sama klasa działa... Musi źle zapisywać dane do $_SESSION['token']... Pododawaj sobie do Token kontrolne wyświetlenia $this -> objStringGenerator i $this -> returnImage. I odpal - zobaczysz co wyrzuci... Mam nadzieję, że pomoże winksmiley.jpg
sp0ns0r
Witam,

Mam identyczny problem. Znalazł już ktoś jego rozwiązanie?? Jakieś pomysły?? Z góry dziękuję za pomoc.

Mam parę spostrzeżeń. Na zwykłej PHP'owej sesji wszystko działa poprawnie. Działa również jeżeli wygenerowany obraz zapisujemy do pliku. Dopiero przy próbie jego wyświetlenia dzieje się to o czym piszę wcześniej autor tego wątku.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.