Fluke
1.12.2010, 11:32:47
Witam.
Chciałem zrobić coś w stylu cache ale na tablicach. Mianowicie jeżeli użytkownik zaloguje się poprawnie to do różnych tablic robię zrzut (prawie) całej bazy. Robię to po to żeby nie łączyć się z bazą za każdym razem kiedy użytkownik przejdzie na inna podstronę. I mam taki mały problem bo nie wiem jak zrobić żeby ta tablica była widoczna wszędzie. Mam Klasę Login.class.php i tam jest metoda loadUser() i jak przejdzie wszystkie warunki to wywołuję klasę cache.class.php z metodą loadChache() która ładuje (prawie) wszystkie tabele do różnych tablic. Przechodząc dalej do metody loadUser() jak user poprawnie się zaloguje i poprawnie załaduje się baza to automatycznie zastaje prze kierowany do index.php. i tutaj mam problem bo nie wiem jak zabardzo zrobić tą tablicę (niby) globalną a nie chcę za bardzo tego umieszczać w tablicy $_SESSION.
Jeszcze wspomnę że klasa loadCache() jest wywoływana tylko raz by załadować a chciałem użyć metody type getTable1, getTable2 itp. by pobierać tablice załadowane.
Czy jest jakieś rozwiązanie, i czy w ogóle to jest dobry pomysł na ten cach?
Moim zdaniem tak bo pozbywamy się zapytań do bazy, ale wolę usłyszeć wypowiedzi ekspertów bo jeszcze nie wiem czy potrzebnie się męczę.
Pozdrawiam.
Quadina
1.12.2010, 11:51:48
Taki cache jest dobry do parametrów do których nie przewidujesz częstych zmian po stronie administratora i użytkownika. To co mówisz jest dość często używane i można tutaj skorzystać z wzorca projektowego singleton. Jednak nie obejdzie się bez użycia tablicy $_SESSION chociażby z tego względu, że nie ma innej drogi nie plikowo/bazodanowej na przenoszenie danych między kolejnymi wywołaniami skryptu. Na dole podaje przykładową reprezentacje takiej klasy.
<?php
class cache {
// ma zapobiec konstruowania obiektu poza uzyciem statycznej funkcji singleton
// chodzi tylko i wylacznie o utrzymanie JEDNEJ instancji tej klasy dla danej sesji
private function __construct(){
}
/**
* @return cache
*/
public static function getInstance
(){ // korzystamy z session uzywajac jakiejs unikalnej nazwy
if(!isset($_SESSION['singleton/instance/cache']) || $_SESSION['singleton/instance/cache'] === null){ $_SESSION['singleton/instance/cache'] = new self();
}
return $_SESSION['singleton/instance/cache'];
}
// wszystkie pozostale elementy moga byc juz takie jak zwykle
private $table1 = null;
private $table2 = null;
public function loadCache(){
$table1 = array(); // ładujemy z bazy czy skąd kolwiek }
public function getTable1(){
return $this->table1;
}
public function getTable1(){
return $this->table2;
}
}
// uzycie gdziekolwiek będziesz zaczynamy od pobrania instancji
// podczas logowania pobierasz dane do cache
cache::getInstance()->loadCache();
// potem wyciagasz juz gotowe dane z tablicy
$table1 = cache::getInstance()->getTable1();
$table2 = cache::getInstance()->getTable2();
WADY:
Niestety takie rozwiązanie ma swoje duże minusy. Przede wszystkim nie jest do końca bezpieczne przechowywanie dużej ilości danych z baz danych w sesji. Nie koniecznie użytkownik może wyświetlić dane, które wyciągniemy - trzeba się po prostu ograniczyć do minimum z minimum w celu optymalizacji tego rozwiązania.
Raczej nie jestem za takim rozwiązaniem, ale mam nadzieje, że choć trochę pomogę
Fluke
1.12.2010, 11:56:58
Pomogłeś

Właśnie chodziło mi o to żeby nie używać $_SESSION ale jak mówisz że się nie da to będzie trzeba...

A na jakiej zasadzie może to być nie bezpieczne? Bo nie wiem czy np: może się rozpaść i wyskoczyć błędy czy np: ktoś może oglądnąć naszą tablicę z danymi?
Quadina
1.12.2010, 12:10:09
W pojęciu obiektowym, wszystko co nie jest obiektem jest niebezpieczne. Inni użytkownicy raczej tego nie zobaczą, w przypadku jakiegoś błędu również nic się nie stanie. Jednak jakiś obiekt może chcieć sobie zmodyfikować nasz cache bez naszej zgody. Z tego względu własnie używa się singletonu i funkcji prywatnych przy konstruktorze. Dzięki temu mamy wszystko w jednym obiekcie i możemy się odwołać do tego skąd tylko chcemy. Unikamy możliwości nieautoryzowanej modyfikacji tej tablicy z innych obiektów. Innymi słowy zachęcam do pełnego uobiektowania swojego projektu, a nie korzystania z odwołań globalnych typu $_SESSION['tablica1']; gdzie każda funkcja może coś tam nam nabigosić.
aart3k
1.12.2010, 12:36:43
Wystarczy że nazwa zmiennej w sesji będzie dosyć unikalna i po sprawie, też nie ma co wciskać wszędzie obiektowości tylko po to żeby ona była, tam gdzie uprości i uporządkuje kod to jak najbardziej.
Sesja jest tutaj dobrym rozwiązaniem, skoro te tablice mają był ładowane per-user, po zalogowaniu.
Fluke
1.12.2010, 13:08:40
A jeszcze takie pytanie co do sesji. Czy jest jakaś możliwość by ktoś mógł podmienić sesje. Jak mamy sprawdzanie sesji czy id sesji przeglądarki jest taki sam jak $_SESSION['session_id']?
Quadina
1.12.2010, 13:15:07
ID sesji jest przechowywane przez cookie nadawane przy pierwszym połączeniu użytkownika z serwerem. Serwer rozpoznaje do ID i podaje skryptowi odpowiednie dane do _SESSION. Niestety jest prosta możliwość podszycia się pod kogoś - wystarczy ukraść mu ciastko i podawać się pod jego ID sesji. Można się przed tym prost zabezpieczyć sprawdzając np. IP klienta przy każdym wywołaniu strony. Możliwość jest, ale [nie]stety bardzo nikłe szanse na użycie jej przez potencjalnego atakującego - musiałby dostać się do komputerów innych użytkowników, albo podsłuchiwać tony pakietów.
@aart3k: wszędzie to nie - ale jak już istnieje klasę cache to ją wykorzystajmy korzystając z wzorów projektowych. Po za tym używanie wszędzie $_SESSION jest dla mnie raczej nie estetyczne, więc jak tylko mogę uciekam od tego. Kwestia przyzwyczajeń programistycznych, bo wydajność na tym poziomie można zaniedbać.
aart3k
1.12.2010, 13:21:46
Jak chcesz zabezpieczyć sesję to sobie zapisuj do niej w momencie logowania IP ($_SERVER['REMOTE_ADDR']). Potem jak masz jakiś init.php czy coś co wrzucasz wszędzie to sobie sprawdź czy to IP się zgadza - wtedy nikt obcy na tą sesję się nie wbije.
Fluke
1.12.2010, 14:56:39
Dokładnie tak mam, sprawdzam czy dana sesja wraz z ip jest taka sama jak tego co przechodzi przez różne strony. A pytanie co do połączeń MySQL. Czy baaardzo zwalnia system czy tylko trochę ale jak mamy przy 1 wyświetleniu 100 zapytań to widać tą różnicę?
To pytanie pewnie czysto teoretyczne bo wszystko zależy od serwera i od przepustowości łącza klienta, ale bazując na tym że ktoś ma dobre łączę.
Np. czysto teoretycznie, ile na tym forum występuje zapytań zanim nam się strona odtworzy, albo taki onet.pl ile tam może być zapytań do bazy danych, ktoś się może orientuje?
Pozdrawiam
Fifi209
1.12.2010, 15:28:57
Cytat(Fluke @ 1.12.2010, 14:56:39 )

A pytanie co do połączeń MySQL. Czy baaardzo zwalnia system czy tylko trochę ale jak mamy przy 1 wyświetleniu 100 zapytań to widać tą różnicę?
To bardziej oznacza, że masz źle zaprojektowaną bazę i cały system. Mi do zainicjowania sesji i wrzucenia potrzebnych danych wystarczy jedno
góra dwa zapytania.
Co do trzymania w sesji - bardzo polecam trzymanie poufnych danych, szczególnie na hostingach dzielonych. ;]
Co do REMOTE_ADDR - takie zabezpieczenie jak zostawienie domu z niezamkniętymi drzwiami, zwykłe live headers/telnet/curl i po sprawie.
aart3k
1.12.2010, 15:29:41
100 zapytań to bardzo dobry wynik, jak chcesz zabić serwer.
Fluke
1.12.2010, 15:40:38
Do tych 100 zapytań to mówiłem bardziej abstrakcyjnie
Fifi209
1.12.2010, 15:44:10
Z zasady pobieraj tylko to co jest Ci aktualnie potrzebne, jeżeli przewidujesz, że zaraz będziesz musiał coś pobrać z bazy a mógłbyś to zrobić od razu - zrób to i cache.
Jeżeli zagmatwałem:
Wchodzisz na stronę np. panelu administratora, wiesz że musisz sprawdzić uprawnienia - ale zaraz! eureka! po wykonaniu akcji znów je sprawdzę - dobrze, że pomyślałem i mam je w cache/sesji.
Wrzucanie wszystkiego do sesji nie jest bezpieczne.
Wrzucanie wszystkiego do cache nie jest optymalne.
Musisz znaleźć złoty środek.
Fluke
1.12.2010, 18:33:44
A jak oceniacie ten przypadek:
Mamy tabele option:
id element wartosc
1 tytuł 'ala ma kota'
2 opis 'Ta ala jest fajna'
3 nazwa 'super ALa'
150 cos 'gowno'
Mamy 2 sposoby:
1) Pobieramy wszystko i zapisujemy w cache
2) Potrzebne na jednej stronie 3 elementy to albo wywołujemy je za pomocą SELECT `opcja1`,`opcja2`,`opcja3` FROM... albo tworzymy funkcję która pobiera dokładnie 1 element i na tej stronie używamy 3x tej funkcji.
Co według was jest najbardziej wydajne?
Fifi209
1.12.2010, 19:46:13
Jeżeli masz coś takiego w bazie oznacza to tylko, że została źle zaprojektowana i masz bajzel.
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.