Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: PHP a współbieżność
Forum PHP.pl > Forum > PHP
Majewicz
Witam, napisałem sobie pewien system i panel administracyjny w języku PHP w oparciu o sesję oraz bazę danych MySQL. Wszystko działa bardzo dobrze ale są 2 problemy związane z współbieżnością, z którymi nie mogę sobie poradzić.

1. Problem pierwszy.
Panelem administracyjnym zarządza dwóch (lub więcej) administratorów. Problem jest taki, że gdy osoba powiedzmy z miasta X się loguje loginem "abc" to inna osoba z innego miasta, powiedzmy Y, też może się zalogować w tym samym czasie na te same konto. Jak to zablokować? Mam parę pomysłów ale niestety żaden z nich nie będzie dobrze do końca działał. Jeden z pomysłów to odpowiednia wartość ustawiana w bazie danych, czyli gdy admin A loguje się do panelu to ustawiana jest mu pewna wartość 1 w bazie (czyli jest zalogowany). Gdy ktoś inny będzie się próbował zalogować na to konto to sprawdzana jest ta wartość (0 to niezalogowany, 1 to zalogowany). W momencie gdy admin A klika na "Wyloguj" to wartość w bazie przyjmuje wartość 0. To myślę by działało dobrze gdyby nie jeden fakt. W momencie gdy admin wyłączy przeglądarkę i się nie wyloguje (albo np. wywali mu korki i komputer się wyłączy) to zmienna w bazie nie powróci do wartości 0 mimo iż faktycznie ten admin nie przebywa już w PA. Skutek tego będzie taki, że nie będzie się mógł zalogować. Jak sobie poradzić z tym problemem? Szukam i szukam i nic nie wychodzi.

2. Problem drugi
Blisko spokrewniony. W panelu admina jest moduł zarządzania stylami CSS. W przypadku gdy w panelu jest zalogowany admin A i B i obaj będą chcieli edytować ten sam styl to wiadomo jak to się skończy. Gdy zmiany wprowadzi admin A a następnie potem admin B to zmiany wprowadzone przez admina A zostaną nadpisane i w ogóle ich nie będzie. Chciałbym to jakoś zrobić, żeby na czas prowadzenia pracy nad danym plikiem była zablokowana jego edycja. Też przez bazę? I znowu ten sam problem z wyłączeniem przeglądarki bądź komputerem bez wylogowania. Jak sobie poradzić z takim czymś, jakie są na to metody?

Z góry dziękuję za pomoc.
Crozin
Po pierwsze to nie ma nic wspólnego z współbieżnością.

Ad. 1: Możesz sprawdzać czas ostatniej aktywności by określić czy sesja już wygasła czy nie. Poszukaj dowolnego wątku na temat "osób online".
Ad. 2: http://forum.php.pl/index.php?showtopic=185206&hl=
Majewicz
Cytat(Crozin @ 8.10.2011, 23:27:46 ) *
Ad. 1: Możesz sprawdzać czas ostatniej aktywności by określić czy sesja już wygasła czy nie. Poszukaj dowolnego wątku na temat "osób online".
A co w przypadku gdy sesja trwa np 3 godziny a ja zamknę przeglądarkę? Np. czas ostatniej aktywności to godzina 21:15. O godzinie 21:17 nagle powiedzmy zabrakło chwilowo prądu. Następnie o godzinie 21:25 chcę się zalogować i nie mogę bo sesja trwa 3 godziny a więc muszę czekać 3 godziny na zalogowanie czyli do 0:15. Jak sobie z tym poradzić?

Cytat(Crozin @ 8.10.2011, 23:27:46 ) *

Poczytałem ale mam pytanie:
Cytat(Crozin @ 4.10.2011, 12:47:02 ) *
Nie powinieneś robić tego w ten sposób. Dodaj sobie w bazie danych kolumnę z czasem ostatniej aktualizacji. Następnie w formularzu edycji wrzuć do ukrytego pola czy tam jako zmienną sesynją tą datę - tak by była ona przesłana do skryptu odpowiedzialnego za wykonanie zapytania UPDATE. Na koniec w skrypcie modyfikującym bazę danych dodaj na początku sprawdzenie czy przesłana data jest równa tej w bazie danych. Jeśli tak, oznacza to że rekord nie został zmodyfikowany w czasie od wyświetlenia formularza do jego wsyłania. Jeżeli zaś jest inna pzekieruj użytkownika spowrotem do formularza edycji i informacją o tym, że rekord został przez kogoś zaktualizowany.
I co dalej? Gdy wprowadzę dużo zmian w różnych miejscach kodu CSS i będę chciał zapisać i wywali mi komunikat, że ktoś zrobił aktualizację w czasie mojej edycji to mam teraz szukać gdzie wprowadzałem zmiany i kopiować do zmodyfikowanego kodu? Czy jak?
Crozin
Żywotność sesji powinieneś raczej liczyć w minutach, nie godzinach. Jednakże pomysł sam z siebie jest raczej słaby (kompletne blokowanie dostępu z dwóch miejsc na raz). Raczej powinieneś rozważyć rozwiązanie stosowane przez Google czy Facebooka w postaci poinformowania, o równoległym zalogowaniu się na konto i możliwości wylogowania "zdublowanych" użytkowników.

Cytat
I co dalej? Gdy wprowadzę dużo zmian w różnych miejscach kodu CSS i będę chciał zapisać i wywali mi komunikat, że ktoś zrobił aktualizację w czasie mojej edycji to mam teraz szukać gdzie wprowadzałem zmiany i kopiować do zmodyfikowanego kodu? Czy jak?
Generalnie możesz poczytać sobie o rozwiązywaniu konfliktów / kolizji w systemach kontroli wersji - sporo materiału o tym znajdziesz w sieci. A różnic pomiędzy dwoma dokumentami nie musisz szukać samemu - komputery też są w stanie to zrobić: diff.
thek
ad1) A czemu nie porównasz danych połączenia? Zwróć uwagę, że dwie różne osoby niemal na bank będą oznaczać różne IP, user-agenta przeglądarki czy inne tego typu dane. Przechowuj więc w sesji je i porównuj przy przechodzeniu między stronami. Jeśli wykryjesz niezgodność - zdecyduj czy killować siedzącego dotychczas, nowego czy może obu i wywalić sesję oraz poinformować, że może być tylko jeden zalogowany na danym koncie w tym samym czasie. Można też inaczej, prościej... Podczas logowania zapisz sobie pewien "odcisk" danych usera (przykładowo md5 z user-agenta). Jeśli nastąpi kolejne zalogowanie, z innym odciskiem, znowu decyduj co robić.

ad2) załóż blokadę na plik. Wejście w panel edycji pliku powinno zablokować dostęp do możliwości edycji dla każdego innego admina. Blokada powinna być zdjęta w momencie zakończenia edycji lub po określonym czasie nieaktywności admina edytującego.
drPayton
Cytat(thek @ 9.10.2011, 00:37:12 ) *
(...)
Blokada powinna być zdjęta w momencie zakończenia edycji lub po określonym czasie nieaktywności admina edytującego.


Nie kojarzę, gdzie widziałem takie rozwiązanie, ale przy edycji takiego zablokowanego (dla innych) rekordu/pliku/whatever admin ma na górze strony box z informacją o czasie pozostałym na edycję (= czasie blokowania), może sobie kliknąc w "przedłuż" i dosteje tym samym kolejne, np 15 minut (akcja oczywiście ajax'em robiona)

To tylko taki dodatek funkcjonalny, całkiem przydatny wink.gif
Majewicz
Cytat(Crozin @ 9.10.2011, 00:33:27 ) *
Żywotność sesji powinieneś raczej liczyć w minutach, nie godzinach.
Tak też mam ustawione, a dokładnie na 1440 sekund.

Cytat(Crozin @ 9.10.2011, 00:33:27 ) *
Raczej powinieneś rozważyć rozwiązanie stosowane przez Google czy Facebooka w postaci poinformowania, o równoległym zalogowaniu się na konto i możliwości wylogowania "zdublowanych" użytkowników.

Cytat(thek @ 9.10.2011, 00:37:12 ) *
ad1) A czemu nie porównasz danych połączenia? Zwróć uwagę, że dwie różne osoby niemal na bank będą oznaczać różne IP, user-agenta przeglądarki czy inne tego typu dane. Przechowuj więc w sesji je i porównuj przy przechodzeniu między stronami. Jeśli wykryjesz niezgodność - zdecyduj czy killować siedzącego dotychczas, nowego czy może obu i wywalić sesję oraz poinformować, że może być tylko jeden zalogowany na danym koncie w tym samym czasie. Można też inaczej, prościej... Podczas logowania zapisz sobie pewien "odcisk" danych usera (przykładowo md5 z user-agenta). Jeśli nastąpi kolejne zalogowanie, z innym odciskiem, znowu decyduj co robić.

Na razie powalczyłem z pierwszym problemem i myślę, że chyba się udało. Zrobiłem to w ten sposób, że zapisuję do bazy danych adres IP administratora, który się zalogował. Porównując datę i czasy logowania, wylogowania i ostatniej aktywności osiągnąłem zamierzony cel czyli gdy zaloguję się na dane konto to już z innego adresu nie mogę się w tym samym czasie na nie zalogować, ale z tego samego ip mogę. Ponadto gdy mam system otwarty w dwóch różnych przeglądarkach jednocześnie to wylogowanie w jednej przeglądarce powoduje wylogowanie też w drugiej. No i dzięki temu, że jest sprawdzanie IP to wyłączenie przeglądarki bez wylogowywania (albo na przykład gdy jest chwilowy brak prądu) umożliwia mi powtórne zalogowanie no chyba, że miałbym inny adres ip to wtedy musiałbym czekać te sesyjne ustalone przeze mnie 1440s.
Pytanie czy zakodowanie adresu ip md5 jest bezpieczne? Taki zakodowany adres ip przechowuję w bazie danych w tabeli z loginami (dla danego loginu rzecz jasna)

Powalczę jeszcze z tymi stylami. Zobaczymy co wyjdzie. Dzięki za naprowadzanie na rozwiązania moich problemów wink.gif
Leliw
Należy pamiętać, że w tej technologii nie ma stałego połączenia, a mechanizm sesji tylko symuluje stałe połączenie.

1. Problem pierwszy nie jest problemem, zapewne chodzi Ci o coś innego. Możesz ustawić krótką sesję (kilka minut) i na każdej stronie dodajesz dodatkowy timer w JavaScript, który wysyła zapytania aby podtrzymać sesję póki strona jest otwarta.
Pamiętanie IP się nie sprawdza jeśli użytkownicy są za maskaradą, albo korzystają zdalnie z tego samego komputera (remote desktop itp.).

2. Wykrywasz, czy między pobraniem danych do edycji ma stronę, a przesłaniem modyfikacji tych danych nie zostały zmodyfikowane przez kogoś innego (np. czas ostatniej modyfikacji lub skrót MD5).
Jeśli chcesz blokować rekord do edycji, to powiąż blokadę z sesją - sesja się kończy, blokady tej sesji też. Jednak, jak użytkownik zrobi sobie edycję w dwóch kartach, to znowu będzie problem.
barthpl
AD1: Nie bawiłem się jeszcze tym (ajax-push) ale zobacz czy to by ci nie pomogło. Podejście z ustawieniem flagi rozwinięte o dodatkową komunikację. Gdy zaloguje się drugi użytkownik (i flaga ustawiona jest na blokowanie dostępu) to wyświetla mu się info że weryfikujesz możliwość edycji a pierwszemu wyświetla się informacja że, ktoś próbuje robić to co on i jeżeli na nią zareaguje (kliknie "pracuje dalej") to drugi użytkownik będzie dalej blokowany jeżeli nie to zmieniasz flagę i pozwalasz pierwszemu na edycję.
by_ikar
Żeby uniknąć czekania aż sesja wygaśnie w przypadku kiedy zmieni się userowi IP (neostrada sama się resetuje co 12 godzin bodajże..) to możesz ustawić sesje nie na określony czas, ale do czasu wygaśnięcia, czyli zamknięcia przeglądarki (czas sesji podajesz jako 0 wówczas). A podczas otwartej przeglądarki, po przechodzeniu na każdą z podstron możesz albo za każdym razem, albo co jakiś określony czas np 10minut regenerować sesję i aktualizować dane (id usera, ip, useragent itp). W bazie dodatkowo ustawić czas aktualizacji rekordu i powiedzmy wszystko powyżej 10min od ostatniej aktualizacji będzie czyszczone. Możesz to czyścić poprzez cron, trigger, lub dodać dodatkowe zapytanie (delete) do update, które będzie wcześniej aktualizować dane w bazie. Tylko jak ustawisz regenerację sesji co 10min to w przypadku kasowania z bazy sesji które są nie aktywne, dodaj więcej niż 10min wink.gif To jest coś na zasadzie userów online, o których pisał @Crozin dzięki temu możesz sprawdzić kto jest online, jak i lepiej kontrolować sesje.
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.