Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [skrypt] Licznik odwiedzin OOP PHP z PDO, Prosta klasa "Licznik" wykorzystująca PDO do połączeń z bazą d
gregherb
post
Post #1





Grupa: Zarejestrowani
Postów: 2
Pomógł: 0
Dołączył: 28.05.2011

Ostrzeżenie: (0%)
-----


Na samym początku wypada się przywitać co też czynię, jako że jestem świeżo po rejestracji na forum. Mam też nadzieję, że nie umknął mi żaden punkt regulaminu i na starcie nie popełniłem jakiegoś "wykroczenia" zamieszczając pierwszy post.

A teraz do rzeczy:

Od dzisiaj studiuję rozszerzenie PDO. Napisałem prostą klasę licznika odwiedzin odpornego na odświeżanie strony. Dane licznika przechowywane są w bazie danych. Konstruktor klasy tworzy nową tabelę jeśli takowa nie istnieje. Więcej szczegółów w komentarzach do metod.

Proszę doświadczonych programistów o:
1. ocenę kodu;
2. wskazówki na co zwracać uwagę;
3. ocenę pod kątem bezpieczeństwa (czy takie wykorzystanie PDO utrudnia SQL Injection?)
4. co można zoptymalizować;
5. opinie czy takie wykorzystanie funkcji unset jest korzystne/dobre, czy też zbędne/złe?
6. Co sądzicie o PDO? Czy pod względem wygody/wydajności/bezpieczeństwa jest lepsze od innych metod? Co polecacie?

Każda konstruktywna krytyka jest mile widziana.

Oto kod:
  1. class Counter {
  2. private $db; //obiekt bazy danych
  3. private $counter; //zmienna zawierająca wartość licznika
  4.  
  5. //Funkcja inicjuje połączenie z bazą danych, wrazie potrzeby tworzy tabelę i ustawia wartość
  6. //licznika. Ponadto ustawia cookie o nazwie visited na wartość true i czas życia 3h.
  7. function __construct($dbName, $user, $password, $host="localhost", $dbType="mysql") {
  8. //w tym miejscu powinny znajdować się instrukcję obsługi pozostałych typów baz danych
  9. $dsn = "$dbType:dbname=$dbName;host=$host;";
  10. try {
  11. $this->db = new PDO($dsn, $user, $password);
  12. } catch (PDOException $e) {
  13. echo "Nieudana próba połączenia: " . $e->getMessage();
  14. }
  15.  
  16. $checkIfTableExists = $this->db->prepare("SELECT * FROM licznik");
  17. if(!$checkIfTableExists->execute()) {
  18. $create = $this->db->prepare("CREATE TABLE licznik(Hits INT)");
  19. $create->execute();
  20. unSet($create);
  21.  
  22. $insert = $this->db->prepare("INSERT INTO licznik VALUES(0)");
  23. $insert->execute();
  24. unSet($insert);
  25. }
  26. unSet($checkIfTableExists);
  27.  
  28. $select = $this->db->prepare("SELECT Hits FROM licznik");
  29. $select->execute();
  30.  
  31. $result = $select->fetch(PDO::FETCH_ASSOC);
  32. unSet($select);
  33.  
  34. if (isSet($_COOKIE['visited'])) {
  35. $this->counter = $result['Hits'];
  36. } else {
  37. $this->counter = $result['Hits'] + 1;
  38.  
  39. $update = $this->db->prepare("UPDATE licznik SET Hits=$this->counter");
  40. $update->execute();
  41. unSet($update);
  42.  
  43. setCookie("visited", "true", time()+3600*3);
  44. }
  45. unSet($result);
  46. }
  47.  
  48. //Funkcja umożliwia ustawienie licznia na dowolną wartość.
  49. function setCounter($val) {
  50. $this->counter = $val;
  51. $update = $this->db->prepare("UPDATE licznik SET Hits=$val");
  52. $update->execute();
  53. unSet($update);
  54. }
  55.  
  56. //Funckja zwraca wartość licznika.
  57. function getCounter() {
  58. return $this->counter;
  59. }
  60.  
  61. //Funkcja ustawia wartość licznika na 0.
  62. function resetCounter() {
  63. $reset = $this->db->prepare("UPDATE licznik SET Hits=0");
  64. $reset->execute();
  65. $this->counter = 0;
  66. unSet($reset);
  67. }
  68.  
  69. //Destruktor klasy Counter.
  70. function __destruct() {
  71. unSet($this->db);
  72. unSet($this->counter);
  73. }
  74. }


Sposób użycia:
  1. $licznik = new Counter("nazwa_bazy", "user", "hasło", "host", "typ_bazy");
  2. echo "Liczba odwiedzin: " . $licznik->getCounter();
  3. unset($licznik);


Ten post edytował gregherb 28.05.2011, 21:57:20
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 5)
-=Peter=-
post
Post #2





Grupa: Zarejestrowani
Postów: 304
Pomógł: 51
Dołączył: 4.02.2005
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Po co korzystasz z unset? Php ma gc, więc jeśli zmienna wyjdzie poza zakres to pamięć zostanie zwolniona - niepotrzebne zaciemnianie kodu.

Korzystasz z prepared statements, lecz w ogóle nie wykorzystujesz ich zalet. Masz na krzyż 4 zapytania, które różnią się tylko parametrem, przygotuj sobie 4 obiekty prepared statement dla każdego z zapytań i te obiekty wykorzystuj do wykonywania zapytań, a nie twórz ich non stop za każdym razem. Będziesz musiał wykorzystać placeholdery (np. w postaci znaku zapytania), a wartosci przekazywać do metody execute - tak też powinno się robić nawet gdy docelowo obiekt PDOStatement ma wykonać tylko jedno zapytanie.

Klasa counter nie powinna nawiązywać połączenia z bazą danych, a dostać już gotowe połączenie.
Go to the top of the page
+Quote Post
gregherb
post
Post #3





Grupa: Zarejestrowani
Postów: 2
Pomógł: 0
Dołączył: 28.05.2011

Ostrzeżenie: (0%)
-----


Dzięki za spostrzeżenia!

Cytat(-=Peter=- @ 28.05.2011, 23:12:30 ) *
(..) przygotuj sobie 4 obiekty prepared statement dla każdego z zapytań i te obiekty wykorzystuj do wykonywania zapytań


Czyli w tym konkretnym przypadku powinienem przygotować po jednym obiekcie dla zapytań select, update, insert, create? Czy tak?

Cytat(-=Peter=- @ 28.05.2011, 23:12:30 ) *
Klasa counter nie powinna nawiązywać połączenia z bazą danych, a dostać już gotowe połączenie.


W tym miejscu nie byłem pewien, czy Counter powinien sam łączyć się z bazą. Dzięki za wyjaśnienie! Czy powinienem przekazywać do niego gotowe połączenie w postaci obiektu PDO?


Jeszcze raz dzięki za odpowiedź i miłej niedzieli.
Go to the top of the page
+Quote Post
Zyx
post
Post #4





Grupa: Zarejestrowani
Postów: 952
Pomógł: 154
Dołączył: 20.01.2007
Skąd: /dev/oracle

Ostrzeżenie: (0%)
-----


Chodzi o zapytania UPDATE:

Kod
$update = $this->db->prepare("UPDATE licznik SET Hits=$val");
$update->execute();


Po co Ci tutaj prepare(), kiedy dane wklejasz bezpośrednio w zapytanie?
Go to the top of the page
+Quote Post
cepa
post
Post #5





Grupa: Zarejestrowani
Postów: 125
Pomógł: 7
Dołączył: 27.01.2010

Ostrzeżenie: (0%)
-----


blad na bledzie (IMG:style_emoticons/default/tongue.gif)

1 - dlaczego tworzysz nowe polaczenie w konstruktorze? nie lepiej wystawic set/get connection aby mozna bylo to zlaczyc z innym kodem?
2 - calkowity brak tranzakcji
3 - tworzenie tabeli w locie!?
4 - duplikacje kodu (brak DRY)
5 - nie robisz lockow na tabelach

ogolnie, licznik nadaje sie jedynie do prostych stronek o niklej ogladalnosci, przy wiekszym ruchu bedzie waskim gardlem a przy duzej konkurencyjnosci bedzie dawal zle wyniki
Go to the top of the page
+Quote Post
Fifi209
post
Post #6





Grupa: Zarejestrowani
Postów: 4 655
Pomógł: 556
Dołączył: 17.03.2009
Skąd: Katowice

Ostrzeżenie: (0%)
-----


Nie wykorzystujesz tego co oferuje PDO, a mam tutaj na myśli dokładnie to co pisał Zyx.
Destruktor możesz wywalić.
resetCounter mógłby najwyżej wywoływać $this->setCounter(0), nie widzę sensu powielania kodu.
getCounter nie zwróci odpowiedniej wartości, jeżeli w czasie wykonywania skryptu kilku innych w tym samym czasie wejdzie na stronie i każdy z nich przesunie licznik o +1 ;]
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 23.08.2025 - 04:38