Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> database class - prosba o opinie
foxmark
post 8.04.2013, 10:23:08
Post #1





Grupa: Zarejestrowani
Postów: 18
Pomógł: 0
Dołączył: 20.03.2004
Skąd: Londyn

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


Witam,

Stawiam 'pierwsze' kroki w projektowaniu obiektowym - bylbym wdzieczny za opinie i komentarze zwlaszcza krytyczne.
Moim celem jest uproszczenie i ujednolicenie sposobu w jaki komunikuje sie z baza danych.
Czy ktos moze wskazac zagrozenia i luki w bezpieczenstwie - czy cos przegapilem albo poprostu o tym nie wiem ?
Czy mozna dodac cos jeszcze co ulatwiloby polaczenie do DB ?

Dziekuje za poswiecony czas.

Ps. wiem tekze ze moge uzyc $db = new mysqli(); ale chcialem stworzyc cos wlasnego.


(config.php)
  1. <?php
  2. defined('DB_HOST') ? null : define('DB_HOST', "localhost");
  3. defined('DB_USER') ? null : define('DB_USER', "root");
  4. defined('DB_PASS') ? null : define('DB_PASS', "");
  5. defined('DB_BASE') ? null : define('DB_BASE', "flex");
  6. defined('DB_PORT') ? null : define('DB_PORT', 3306);
  7. defined('DEBUG_MODE') ? null : define('DEBUG_MODE', TRUE);
  8. defined('DEBUG_EMAIL') ? null : define('DEBUG_EMAIL', "email@server.com");
  9. ?>



(mysqldatabase.php)
  1. <?php
  2. require_once('config.php');
  3. /**
  4.  * Description of mysqldatabase
  5.  * @author Pawel Pasich
  6.  */
  7.  
  8. class mysqldatabase {
  9. private $connection;
  10. private $last_query;
  11. public $error;
  12.  
  13.  
  14. public function __construct() {
  15. $this->open_connection();
  16. }
  17.  
  18. private function open_connection(){
  19. if (function_exists("mysqli_connect")) {
  20. $db = @mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_BASE, DB_PORT);
  21. if ($db) {
  22. $this->connection = $db;
  23. } else {
  24. $this->connection = FALSE;
  25. $this->error = "Unable to connect to DB: ";
  26. if (DEBUG_MODE) {
  27. $this->error .= mysqli_connect_error();
  28. $this->send_alert(DEBUG_EMAIL, $this->error);
  29. }
  30. }
  31. } else {
  32. if (DEBUG_MODE) {
  33. $this->error = "Function mysqli_connect not active";
  34. $this->send_alert(DEBUG_EMAIL, $this->error);
  35. }
  36. $this->connection = FALSE;
  37. }
  38. }
  39.  
  40. public function query($sql) {
  41. if ($this->connection) {
  42. $this->last_query = $sql;
  43. $result = mysqli_query($this->connection, htmlspecialchars($sql, ENT_QUOTES));
  44. if ($result) {
  45. return $result;
  46. } else {
  47. $this->error = "Query error: ";
  48. if (DEBUG_MODE) {
  49. $this->error .= mysqli_error($this->connection);
  50. $this->send_alert(DEBUG_EMAIL, $this->error);
  51. }
  52. return FALSE;
  53. }
  54. } else {
  55. return FALSE;
  56. }
  57. }
  58.  
  59. public function fetch_array_assoc($result) {
  60. $data = array();
  61. if ($result) {
  62. while ($row = mysqli_fetch_assoc($result)) {
  63. $data[] = $row;
  64. }
  65. }
  66. return $data;
  67. }
  68.  
  69. public function fetch_array_object($result) {
  70. $data = array();
  71. if ($result) {
  72. while($row = mysqli_fetch_object($result)) {
  73. $data[] = $row;
  74. }
  75. }
  76. return $data;
  77. }
  78.  
  79. public function fetch_array_num($result) {
  80. $data = array();
  81. if ($result) {
  82. while($row = mysqli_fetch_array($result, MYSQLI_NUM)) {
  83. $data[] = $row;
  84. }
  85. }
  86. return $data;
  87. }
  88.  
  89. public function num_rows($result) {
  90. return mysqli_num_rows($result);
  91. }
  92.  
  93. public function insert_id() {
  94. return mysqli_insert_id($this->connection);
  95. }
  96.  
  97. public function affected_rows() {
  98. return mysqli_affected_rows($this->connection);
  99. }
  100.  
  101. public function close_connection() {
  102. if ($this->connection) {
  103. mysqli_close($this->connection);
  104. unset($this->connection);
  105. }
  106. }
  107.  
  108. private function send_alert($email, $text) {
  109. @mail($email, 'mysql class error report', $text, 'From: '.$email);
  110. }
  111.  
  112.  
  113. public function __destruct() {
  114. $this->close_connection();
  115. }
  116. }
  117. ?>


Ten post edytował foxmark 8.04.2013, 10:25:27
Go to the top of the page
+Quote Post
!*!
post 8.04.2013, 10:55:47
Post #2





Grupa: Zarejestrowani
Postów: 4 298
Pomógł: 447
Dołączył: 16.11.2006

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


Tylko w czym Twoje rozwiązanie jest lepsze od samego PDO, lub nadbudówki na nie?
I czy:

  1. public function __destruct()
  2. {
  3. $this->close_connection();
  4. }


Nie zablokuje działania w niektórych przypadkach. Usuń też @ z kodu.

Ten post edytował !*! 8.04.2013, 10:57:22


--------------------
Nie udzielam pomocy poprzez PW i nie mam GG.
Niektóre języki programowania, na przykład C# są znane z niezwykłej przenośności (kompatybilność ze wszystkimi wersjami Visty jest wiele warta).
Go to the top of the page
+Quote Post
emp
post 8.04.2013, 11:15:58
Post #3





Grupa: Zarejestrowani
Postów: 195
Pomógł: 14
Dołączył: 12.01.2006
Skąd: Gotham City

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


Jeżeli stwiasz pierwsze kroki to skup się na robieniu obiektów dziedziny.
Przygotowuj zapytania, korzystaj z prepejrów, binduj parametry, korzystaj z tranzakcji.
Daruj sobie defined. Stwórz klase konfiguracyjna z stałymi lub statycznymi polami.
Używaj przestrzeni nazw. Korzystaj z spl_autoloader zamiast z rekłirów i inkludów.
Jeżeli chcesz uprościć komunikacje z bazą to się z nią nie komunikuj bezpośrednio. Korzystasz z obiektów dziedziny , a to gdzie to jest utrwalane czy z jakiego źródła pobierane nie ma znaczeia.
Obiekt dziedziny->Odwzorowanie danych->Polaczenie z baza. Wzorców projektówych, znanych rozwiązań, dobrych praktyk odnosnie utrwalania jest masa, poznaj je.
Przeczytaj to architektura-systemow-zarzadzania-przedsiebiorstwem-wzorce-projektowe-martin-fowler
Jeżeli przedstawiasz klase to przedstaw też w jaki sposób z niej korzystasz i opisz jakie korzyści ci daje.

Ten post edytował emp 8.04.2013, 11:29:52


--------------------
Temat zamykam i przenoszę do Bangladeszu.
To jest wiadomość śmierci jeśli ją czytasz to znaczy że pozostało ci 30 sekund życia, więc lepiej zacznij się modlić.
Go to the top of the page
+Quote Post
foxmark
post 8.04.2013, 12:01:38
Post #4





Grupa: Zarejestrowani
Postów: 18
Pomógł: 0
Dołączył: 20.03.2004
Skąd: Londyn

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


Cytat(!*! @ 8.04.2013, 10:55:47 ) *
Tylko w czym Twoje rozwiązanie jest lepsze od samego PDO, lub nadbudówki na nie?
I czy:

  1. public function __destruct()
  2. {
  3. $this->close_connection();
  4. }


Nie zablokuje działania w niektórych przypadkach. Usuń też @ z kodu.


Dziekuje za Twoja opinie.
* myslalem o wylaczeniu __destruct() - dzieki za rade.
* @ uzylem tylko dlatego ze scrypt php karmi aplikacje (oparta o flash - adobe flex) nie wyrzucam nic na ekranie i takie zachowanie konczy sie bledem aplikacji.
* PDO to nastepny krok - narazie staram sie poznac zasady dzialania i latwiej jest mi poslugiwac sie znanym juz mysqli.

Cytat(emp @ 8.04.2013, 11:15:58 ) *
Jeżeli stwiasz pierwsze kroki to skup się na robieniu obiektów dziedziny.
Przygotowuj zapytania, korzystaj z prepejrów, binduj parametry, korzystaj z tranzakcji.
Daruj sobie defined. Stwórz klase konfiguracyjna z stałymi lub statycznymi polami.
Używaj przestrzeni nazw. Korzystaj z spl_autoloader zamiast z rekłirów i inkludów.
Jeżeli chcesz uprościć komunikacje z bazą to się z nią nie komunikuj bezpośrednio. Korzystasz z obiektów dziedziny , a to gdzie to jest utrwalane czy z jakiego źródła pobierane nie ma znaczeia.
Obiekt dziedziny->Odwzorowanie danych->Polaczenie z baza. Wzorców projektówych, znanych rozwiązań, dobrych praktyk odnosnie utrwalania jest masa, poznaj je.
Przeczytaj to architektura-systemow-zarzadzania-przedsiebiorstwem-wzorce-projektowe-martin-fowler
Jeżeli przedstawiasz klase to przedstaw też w jaki sposób z niej korzystasz i opisz jakie korzyści ci daje.


Dzieki za inforamcje.
* Postaram sie przedstawic statyczna wersje clasy.
* Ponizej podaje uzycie classy - oczywiscie normalnie jako czesc metody innej klasy (tutaj tylko zwykly kod).
  1. require_once('../private/mysqldatabase.php');
  2. $db = new mysqldatabase();
  3. $sql = "SELECT * FROM `emplo`";
  4. $result = $db->query($sql);
  5. $array = $db->fetch_array_object($result);


* staralem sie znalesc w sieci jakis dobry tutorial jak zbudowac taka klase ale bez wiekszego rezultatu - czy znasz cos wartego polecenia na czym moglbym sie doksztalcac ? wink.gif

Ten post edytował foxmark 8.04.2013, 11:53:25
Go to the top of the page
+Quote Post
emp
post 8.04.2013, 14:35:42
Post #5





Grupa: Zarejestrowani
Postów: 195
Pomógł: 14
Dołączył: 12.01.2006
Skąd: Gotham City

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


Też kiedyś naskrobałem podobna klase
  1. <?php
  2. namespace antaeus_api\moduly\narzedzia;
  3.  
  4. /**
  5.  * Klasa pomocnicza dla testów jednostkowych nie używać w innym kontekście
  6.  *
  7.  * Jest to klasa pomocnicza wykorzystywana przy weryfikacji poprawności testów jednostkowych
  8.  * Służy to szybkiego konstruowania polaczen pdo i wykonaywanie nie definiowania zapytań
  9.  */
  10. class Sql_mini {
  11.  
  12. private $polaczenie;
  13. private $wynik_sql;
  14. private $wyrazenie_sql;
  15.  
  16. public function __construct($wyrazenie_sql = null, $polaczenie = null) {
  17.  
  18. if ($polaczenie == null)
  19. $polaczenie = \data\Konfiguracja::podaj_domyslne_polaczenie();
  20.  
  21. $this->wyrazenie_sql = $wyrazenie_sql;
  22. $this->polaczenie = self::utworz_polaczenie($polaczenie);
  23. }
  24.  
  25. public static function utworz_polaczenie($polaczenie = null) {
  26.  
  27. if ($polaczenie == null)
  28. $polaczenie = \data\Konfiguracja::podaj_domyslne_polaczenie();
  29.  
  30. $nazwa_zrodla_danych = self::utworz_nazwe_zrodla_danych($polaczenie);
  31.  
  32. try {
  33. $polaczenie = new \PDO($nazwa_zrodla_danych, \data\Konfiguracja::$polaczenia[$polaczenie]['uzytkownik'], \data\Konfiguracja::$polaczenia[$polaczenie]['haslo']);
  34. } catch (PDOException $wyjatek) {
  35. throw new \Exception($wyjatek->getMessage() . ' ' . $nazwa_zrodla_danych);
  36. }
  37.  
  38. return $polaczenie;
  39. }
  40.  
  41. public static function utworz_nazwe_zrodla_danych($polaczenie = null) {
  42.  
  43. if ($polaczenie == null)
  44. $polaczenie = \data\Konfiguracja::podaj_domyslne_polaczenie();
  45.  
  46. $nazwa_zrodla_danych = \data\Konfiguracja::$polaczenia[$polaczenie]['sterownik'] .
  47. ':dbname=' . \data\Konfiguracja::$polaczenia[$polaczenie]['baza'] .
  48. ';host=' . \data\Konfiguracja::$polaczenia[$polaczenie]['host'] .
  49. ';port=' . \data\Konfiguracja::$polaczenia[$polaczenie]['port'];
  50.  
  51. return $nazwa_zrodla_danych;
  52. }
  53.  
  54. public function wykonaj_zapytanie($wyrazenie_sql = null) {
  55.  
  56. if ($wyrazenie_sql == null)
  57. $wyrazenie_sql = $this->wyrazenie_sql;
  58. else
  59. $this->wyrazenie_sql = $wyrazenie_sql;
  60.  
  61. $this->wynik_sql = $this->polaczenie->query($wyrazenie_sql);
  62.  
  63. if (!$this->wynik_sql) {
  64. throw new \Exception($wyrazenie_sql . ' ' . $this->podaj_ostatni_blad());
  65. }
  66.  
  67. return $this;
  68. }
  69.  
  70. private function podaj_ostatni_blad() {
  71. $blad = "";
  72. foreach ($this->polaczenie->errorInfo() as $blad_tmp)
  73. $blad = $blad . ' ' . $blad_tmp;
  74.  
  75. return $blad;
  76. }
  77.  
  78. public function podaj_wiersz() {
  79. return $this->wynik_sql->fetch();
  80. }
  81.  
  82. public function podaj_ilosc_wierszy() {
  83. return $this->wynik_sql->rowCount();
  84. }
  85.  
  86. public function podaj_wiersze() {
  87. return $this->wynik_sql->fetchAll();
  88. }
  89.  
  90. public function podaj_ilosc_kolumn() {
  91. return $this->wynik_sql->columnCount();
  92. }
  93.  
  94. public function podaj_wartosc() {
  95. if ($this->podaj_ilosc_kolumn() > 0) {
  96. $wiersz = $this->podaj_wiersz();
  97.  
  98. if (is_array($wiersz)) {
  99. foreach ($wiersz as $wartosc)
  100. return $wartosc;
  101. }
  102. else return null ;
  103. } else
  104. return null;
  105. }
  106.  
  107. }
  108.  
  109. ?>


Użycie
  1. $sql_mini = new \antaeus_api\moduly\narzedzia\Sql_mini();
  2. $ilosc_powiazan = $sql_mini->wykonaj_zapytanie('select * from role_uprawnienia where rola_id =' . $rola->podaj_id())->podaj_ilosc_wierszy();
  3. $this->assertEquals(0, $ilosc_powiazan);


Takiej klasy nie używam przy produkcji oprogramowania. Zawsze korzystam z obiektów dziedziny i wzorca data maper w szczegolnych przypadkach korzystam z podobnej klasy ale opartej na prepejrach i zamknietej w kontekście tranzakcji, ecz jest to tylko opakowanie pdo. Wtedy korzystam z tego tak
  1. $zapytanie_sql = $polaczenie->utworz_zapytanie(\antaeus_api\moduly\wydruki\sql\Sql::szablon_wydruku_dla_typu);
  2. $wiersz = $zapytanie_sql->wykonaj(array($typ_elementu))->podaj_wiersz();

To tego rozwiązania mam Fabryke_polaczen, klase polaczenia i klase sql która wygląda tak
  1. <?php
  2.  
  3. namespace antaeus_api\moduly\rdzen\fabryka_polaczen;
  4.  
  5. class Zapytanie_sql {
  6.  
  7. private $sql;
  8. private $polaczenie;
  9.  
  10. public function __construct($tresc_zapytania = null, $polaczenie = null) {
  11. if ($polaczenie == null)
  12. $this->polaczenie = Fabryka_polaczen::podaj_polaczenie();
  13. else
  14. $this->polaczenie = $polaczenie;
  15.  
  16. if ($tresc_zapytania != null) {
  17. if (is_array($tresc_zapytania)) {
  18. $this->sql = array();
  19. foreach ($tresc_zapytania as $klucz => $zapytanie)
  20. $this->sql[$klucz] = $this->polaczenie->podaj_zasob()->prepare($zapytanie);
  21. }
  22. else
  23. $this->sql = $this->polaczenie->podaj_zasob()->prepare($tresc_zapytania);
  24. }
  25. }
  26.  
  27. public function ilosc_zmienionych_rekordow() {
  28. return $this->sql->rowCount();
  29. }
  30.  
  31. public function wykonaj($parametry = array()) {
  32. $wynik = $this->sql->execute($parametry);
  33.  
  34. if (!$wynik) {
  35. $parametry_napis = "<br>";
  36. foreach ($parametry as $klucz => $parmetr) {
  37. $parametry_napis = $parametry_napis . '<b>' . $klucz . ".</b> " . $parmetr . "<br>";
  38. }
  39.  
  40. throw new \Exception('Błędne zapytanie <br><br><i>' . $this->sql->queryString . '</i><br>' . $parametry_napis . '<br>' . $this->polaczenie->podaj_ostatni_blad(), 2);
  41. }
  42.  
  43. return $this;
  44. }
  45.  
  46. public function podaj_wartosc() {
  47. if ($this->podaj_ilosc_wierszy() > 0) {
  48. $wiersz = $this->podaj_wiersz();
  49. foreach ($wiersz as $wartosc)
  50. return $wartosc;
  51. }
  52. else
  53. return null;
  54. }
  55.  
  56. public function przygotuj_zapytanie($tresc_zapytania) {
  57. if ($tresc_zapytania != null)
  58. $this->sql = $this->polaczenie->podaj_zasob()->prepare($tresc_zapytania);
  59. }
  60.  
  61. public function podaj_ilosc_kolumn() {
  62. return $this->sql->columnCount();
  63. }
  64.  
  65. public function zamknij_kursor() {
  66. $this->sql->closeCursor();
  67. }
  68.  
  69. public function podaj_wiersz() {
  70. return $this->sql->fetch();
  71. }
  72.  
  73. public function podaj_ilosc_wierszy() {
  74. return $this->sql->rowCount();
  75. }
  76.  
  77. public function podaj_wiersze() {
  78. return $this->sql->fetchAll(\PDO::FETCH_ASSOC);
  79. }
  80.  
  81. }
  82.  
  83. ?>


--------------------
Temat zamykam i przenoszę do Bangladeszu.
To jest wiadomość śmierci jeśli ją czytasz to znaczy że pozostało ci 30 sekund życia, więc lepiej zacznij się modlić.
Go to the top of the page
+Quote Post
foxmark
post 17.04.2013, 12:17:32
Post #6





Grupa: Zarejestrowani
Postów: 18
Pomógł: 0
Dołączył: 20.03.2004
Skąd: Londyn

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


Cytat(emp @ 8.04.2013, 14:35:42 ) *
Też kiedyś naskrobałem podobna klase ...


Dziekuje za kod - zerkne przez weekend czy bede w stanie go zrozumiec wink.gif

Cytat(emp @ 8.04.2013, 11:15:58 ) *
Przygotowuj zapytania, korzystaj z prepejrów, binduj parametry, korzystaj z tranzakcji.

Daruj sobie defined. Stwórz klase konfiguracyjna z stałymi lub statycznymi polami.

Używaj przestrzeni nazw. Korzystaj z spl_autoloader zamiast z rekłirów i inkludów.

...


Witam ponownie, wiem juz smile.gif ze powininem uzywac mysqli_prepare -> mysqli_stmt_bind_param -> mysqli_stmt_execute zeby poprawic szybkosc i bezpieczenstwo
napotkalem jednak problem - chce dynamicznie kontrolowac ilosc zmiennych ktore wysylam.

czytalem http://ca.php.net/manual/en/mysqli-stmt.bi...aram.php#104073

i do swojej klasy dodalem 3 nowe metody - wszystko dziala (ale nie wiem czemu sad.gif ) - chcialbym zrozumiec co sie dzieje w:
  1.  
  2. $ref = new ReflectionClass('mysqli_stmt');
  3. $method = $ref->getMethod("bind_param");
  4. $method->invokeArgs($stmt, $refArr);


to sa metody ktore dodalem

  1. public function prepare_query($sql) {
  2. return mysqli_prepare($this->connection, $sql);
  3. }
  4.  
  5. public function dynamic_bind($stmt, $refArr, $return_id=FALSE) {
  6. if (($stmt) && (!empty($refArr))) {
  7. $ref = new ReflectionClass('mysqli_stmt');
  8. $method = $ref->getMethod("bind_param");
  9. $method->invokeArgs($stmt, $refArr);
  10. $result = $this->execute_query($stmt);
  11. if ($return_id) {
  12. return $this->insert_id();
  13. } else {
  14. return $result;
  15. }
  16. } else {
  17. return FALSE;
  18. }
  19. }
  20.  
  21. public function execute_query($stmt) {
  22. return mysqli_stmt_execute($stmt);
  23. }


tutaj uzycie (wewnatrz innej klasy):

  1.  
  2. public function fct_dispatch_batch($user, $array, $ex_po, $reason) {
  3. $result = false;
  4. $date = date('Y-m-d H:i:s');
  5. $int_po = date('YmdHis-W-N');
  6. $ex_po = $this->sql_con->escape($ex_po);
  7. $sql = "INSERT INTO test (`f2`, `f3`, `f4`) VALUES (?, ?, ?);";
  8. $stmt = $this->sql_con->prepare_query($sql);
  9. foreach ($array as $value => $key) {
  10. $refArr = array("ssi", "$date", "$user", "$key->id");
  11. $result = $this->sql_con->dynamic_bind($stmt, $refArr);
  12. }
  13. return $result;
  14. }


czy moge bezpiecznie uzywac tej metody? czy cos jest z tym nie tak?

kolejne pytanie:
korzystaj z tranzakcji - czy musze uzywac tranzakcji zawsze czy tylko w ciagu zapytan zaleznych od siebie - i jesli musze jak zaczac korzystac z tranzakcji (znam tylko definicje ale nie znam zasad dzialania ani uzycia)
Gdzie moge znalesc dodatkowe informacje?


Dziekuje za poswiecony mi czas.
Pozdrawiam!

Ten post edytował foxmark 17.04.2013, 15:17:23
Go to the top of the page
+Quote Post

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

 



RSS Wersja Lo-Fi Aktualny czas: 27.04.2024 - 14:19