Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [mysql] Przejscie na PDO, najlepszy sposób?
Forum PHP.pl > Forum > Bazy danych
starterrrrr
Witam.

Zarządzam aplikacją, która korzysta z przestażałych już funkcji mysql w php.
Chciałem przejśc na PDO, prosże o podpowiedź jak najszybciej to można zrobić.

Do każdego pliku dołączany jest plik connect.php, który zawiera funkcje połączenia z bażą danych:

  1. //PLIK: CONNECT.PHP
  2.  
  3. function connection($wybrana_baza = '') {
  4.  
  5. global $dir_functions;
  6. //$wybrana_baza = '_public';
  7.  
  8. include($dir_functions.'/config'.$wybrana_baza.'.php');
  9. global $conn;
  10.  
  11. if($conn) {
  12. return $conn;
  13. } else {
  14. $conn = mysql_connect($dbhost,$dbuser,$dbpass);
  15. if (!$conn || !mysql_select_db($db,$conn)) {
  16. return 0;
  17. } else {
  18. mysql_query('SET NAMES utf8');
  19. mysql_query('SET CHARACTER SET utf8');
  20. mysql_query("SET collation_connection = utf8_polish_ci");
  21. return $conn;
  22. }
  23. }
  24. }
  25.  
  26. function sql($query) {
  27. global $zap;
  28. if(!($conn = connection($wybrana_baza))) {
  29. return 0;
  30.  
  31. } else {
  32. $result = mysql_query($query,$conn);
  33.  
  34. if(!$result) {
  35. print('<DIV>Wystąpił błąd:<BR>['.$query.']<BR>['.mysql_error().']</DIV>');
  36. } else {
  37. return $result;
  38. }
  39. }
  40. }
  41.  
  42. //PLIK: CONFIG.PHP:
  43.  
  44.  
  45. $dbhost = '....';
  46. $dbuser = '....';
  47. $dbpass = '...';
  48. $db = '....';
  49. $dbprefix = '....';
  50.  


Następnie w kodzie korzystam z funkcji sql(). Przykłady:

  1. //update
  2. sql("UPDATE ".$dbprefix."news SET zablokuj = '1' WHERE id = '".del($zmienna)."';");
  3.  
  4. //insert
  5. $max_id = oblicz_max('news', 'id');
  6. sql("INSERT INTO ".$dbprefix."news (id, tytul, rozwiniecie) VALUES ('".$max_id."','".del($tytul)."','".del($rozwiniecie)."')");
  7.  
  8.  
  9. //select
  10. $result = sql("SELECT * FROM ".$dbprefix."news WHERE id='".del($id)."' ORDER BY $sort $jak LIMIT $start,$limit");
  11. while($row = mysql_fetch_array($result)) {
  12.  
  13. print(' - '. $row['id'].' '.$row['rozwiniecie']);
  14.  
  15. }


Jak to można najlepiej zrobić? Warto modyfikowac funkcje sql(), czy po prostu, po kolei kolejne moduły przerabiac na PDO i chwilowo korzystac z obu mechanizmów?

Prosze o jakaś podpowiedź, szukałem na forach, ale nie znalazłem konkretnych przypadków. Troche sie obawiam, że bede musiałz dwa tygodnie siedziec nad tym :/
nospor
Jesli wszedzie korzystasz z funkcji connection() i sql() to na razie wystarczy ze tylko tam zmienisz, czyli 5 minut roboty smile.gif

A z czasem mozesz sobie to rozbudowac o pelne wykorzystanie PDO jak bindowanie
Lion
Oczyść obecny kod z zbędnych instrukcji, a następnie opakuj swoją funkcją connection PDO. Takie rozwiązanie szybko pozwoli Ci uruchomić aplikację, jednak stracisz takie funkcjonalności jak ochrona przez SQL injection (poprzez brak ww. bindowania) oraz prepared statements które mogłoby przyśpieszyć wykonywanie zapytań. Możesz coś znaleźć w Internecie wyszukując "PDO wrapper".
viking
Albo najłatwiej na szybko zastąpić ten kod strukturalnym mysqli a w przyszłości pomyśleć jak to przepisać poprawnie.
nospor
@viking ale po co? Przeciez on musi to zmienic tylko w dwoch funkcjach to niech zmieni od razu na PDO.
viking
Bo choćby struktura funkcji sql sugeruje że to nie jest cały kod. Pisanie tego dalej w taki sposób to robienie jeszcze większego śmietnika. IMO lepiej teraz szybko wymienić zło na trochę mniejsze zło niż brnąć dalej w taki bajzel.
starterrrrr
Cytat(Lion @ 3.08.2016, 20:08:12 ) *
Oczyść obecny kod z zbędnych instrukcji, a następnie opakuj swoją funkcją connection PDO. Takie rozwiązanie szybko pozwoli Ci uruchomić aplikację, jednak stracisz takie funkcjonalności jak ochrona przez SQL injection (poprzez brak ww. bindowania) oraz prepared statements które mogłoby przyśpieszyć wykonywanie zapytań. Możesz coś znaleźć w Internecie wyszukując "PDO wrapper".



tak zrobie, z czasem bede poszczególne elementy zastępował zapytaniami z bindowaniem i prepared statements.

Funkcje sql() przerobiłem tak:

  1. function sql($query) {
  2.  
  3. global $db;
  4. global $dbuser;
  5. global $dbpass;
  6. global $dbhost;
  7.  
  8. $db = new PDO('mysql:host='.$dbhost.';dbname='.$db, $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'") );
  9. try {
  10. $stmt = $db->prepare( $query );
  11. $stmt->execute();
  12.  
  13. }
  14. catch (PDOException $e)
  15. {
  16. echo $e->getMessage();
  17. ///die();
  18. }
  19.  
  20. }


Wydaje mi się, że coś jest nie tak, funkcja powinna zwracać chyhba jakas wartość.

Musze zamienić $row = mysql_fetch_array($result) na $row = $stmt->fetch(PDO::FETCH_ASSOC);


------------ EDIT -----

WERSJA 2

  1. function sql($query) {
  2.  
  3. global $db;
  4. global $dbuser;
  5. global $dbpass;
  6. global $dbhost;
  7.  
  8. $db = new PDO('mysql:host='.$dbhost.';dbname='.$db, $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'") );
  9. try {
  10.  
  11. $result = $db->query( $query ) ;
  12. return $result;
  13. }
  14. catch (PDOException $e)
  15. {
  16. echo $e->getMessage();
  17. ///die();
  18. }
  19.  
  20. }
  21.  
  22.  
  23. //wcześniej dla SELECT
  24. $result = sql("SELECT ... ");
  25. while($row = mysql_fetch_array($result)) { ... }
  26.  
  27. //teraz
  28. $result = sql("SELECT ... ");
  29. while($row = $result->fetch ()) { ... }
  30.  
  31.  
  32. //dla UPDATE, DELETE trzeba bedzie zmodyfikowac kod w całej aplikacji.
  33. $result = sql(" UPDATE ...");
  34. $result->execute(); //tutaj nie jestem pewien
viking
Ja bym użył metodę 1 z drobną modyfikacją. Do funkcji przekazuj ($query, array $params = null) i $params może być przekazane do execute(). Dzięki temu miałbyś bindowanie. Funkcja może zwracać $stmt.
nospor
Cytat
Bo choćby struktura funkcji sql sugeruje że to nie jest cały kod. Pisanie tego dalej w taki sposób to robienie jeszcze większego śmietnika. IMO lepiej teraz szybko wymienić zło na trochę mniejsze zło niż brnąć dalej w taki bajzel.
Tak, masz racje. Zupelnie nie zauwazylem ze pozniej po sql() jest zwykle mysql_fetch_array.
starterrrrr
Cytat(nospor @ 4.08.2016, 10:59:11 ) *
Tak, masz racje. Zupelnie nie zauwazylem ze pozniej po sql() jest zwykle mysql_fetch_array.



Czyli jak byście proponowali przerobić całość?
nospor
Tak jak napisal viking: zastapic to libem mysqli w wersji strukturalnej- zmiany beda male i szybko powinienies to zmienic. A pozniej na spokojnie stopniowo przerzucic sie na PDO
starterrrrr
Witam.
Dziekuje za podpowiedzi, zrobiłem tak jak viking kazał, przeszedłem najpierw na MySQLi a z czasem bede migrował na PDO.

Jest jednak pewien problem, przestał działac mechanizm SQL_CALC_FOUND_ROWS przy wykorzystaniu funkcji MySQLi w wersji proceduralnej.
Szukałem na forach zagranicznych, jest pełno podpowiedzi, ale nie dziąłają żadne.

  1.  
  2. function sql($query) {
  3. global $dbhost;
  4. global $dbuser;
  5. global $dbpass;
  6. global $db;
  7.  
  8. $link = mysqli_connect($dbhost, $dbuser, $dbpass, $db);
  9. mysqli_set_charset($link,"utf8");
  10.  
  11. if (mysqli_connect_errno()) {
  12. printf("Błąd połączenia z bazą: %s\n", mysqli_connect_error());
  13. exit();
  14. }
  15.  
  16. $result = mysqli_query($link, $query);
  17.  
  18. if (!$result) {
  19. printf("Błąd bazy danych: %s\n", mysqli_error($link));
  20. }
  21.  
  22. return $result;
  23. mysqli_close($link);
  24. }
  25.  
  26. //zapytanie
  27. $result = sql(" SELECT SQL_CALC_FOUND_ROWS, * FROM tabela WHERE ... LIMIT 20-60;");
  28. while ($row = mysql_fetch_assoc($result)) {
  29. ...
  30. }
  31.  
  32. $result_ilosc = sql("SELECT FOUND_ROWS() as ilosc_pozycji;"); //obliczamy ilosc pozycji
  33. $total = mysqli_fetch_assoc($result_ilosc);
  34. $l_odp = $total['ilosc_pozycji'];
  35.  
  36. ///$l_odp - nie zwraca wartosci :/


Powyżej przedstawiłem jak wygląda mój kod, nie stety nie zwraca mi ilości wszystkich wpisów.
trueblue
Każde zapytanie otwiera nowe połączenie z bazą.
mmmmmmm
Nie podaje ci ilości, bo wcześniej się wywala errorem.
W tej linii:
while ($row = mysql_fetch_assoc($result)) {

LIMIT 20-60 też jest fajne...
starterrrrr
Witam Ponownie. PDO jest juz w podstawowym wymiarze opanowane, jednak daje się odczuć brak doświadczenia w tym mechaniźmnie.


Mam zapytanie SELECT, które posiada warunki w klauzuli WHERE.
Przed tym zapytaniem SQL w kodzie php mam kilka waruinków, które w zależności od zmiennej, wstawiaja dodatkowe warunki do zapytania, jak takie coś bindować?



  1.  
  2. $dodatek_sql = '';
  3. if ($dodaj_kod == 1) {
  4. $dodatek_sql = ' AND sprawdzony=$sprawdzony ';
  5. }
  6.  
  7. $stmt = $db->prepare(
  8. "SELECT * FROM tabela WHERE login=:login AND haslo=:haslo $dodatek_sql "
  9. );
  10. $stmt->bindValue(':login', $login, PDO::PARAM_STR);
  11. $stmt->bindValue(':haslo', $haslo, PDO::PARAM_STR);
  12. $stmt->execute();
  13. $uzytkownicy = $stmt->fetchAll(PDO::FETCH_ASSOC);


Jak przebindować zmienną $dodatek_sql, albo $sprawdzony, czy cala czesc warunku.


Jeszczejedno pytanie. Czy za kazdym razem musze takie zapytanie dawac w TRY {} CATCH zeby przejmowac bledy, czy zrobic jakas funkcje, do ktorej bede przekazywal parametyry laczenia?
Tomplus
Wykonaj prepare() dużo wcześniej, a pod prepare dodaj do warunku kolejny bind.

  1. if ($dodaj_kod == 1) {
  2. $dodatek_sql = ' AND sprawdzony = :sprawdz ';
  3. $stmt->bindValue(':sprawdz', $sprawdzony, PDO::PARAM_BOOL); //_INT
  4. }
starterrrrr
Cytat(Tomplus @ 25.10.2016, 19:18:20 ) *
Wykonaj prepare() dużo wcześniej, a pod prepare dodaj do warunku kolejny bind.

  1. if ($dodaj_kod == 1) {
  2. $dodatek_sql = ' AND sprawdzony = :sprawdz ';
  3. $stmt->bindValue(':sprawdz', $sprawdzony, PDO::PARAM_BOOL); //_INT
  4. }


To bedzie problemem, w skrypcie jest ze 40 zapytań w jednym pliku php, narobi sie balagan :/

Myślałem, żeby cały ten kawalek kodu bindowac:

  1.  
  2. $dodatek_sql = '';
  3. if ($dodaj_kod == 1) {
  4. $dodatek_sql = ' AND sprawdzony="'.$sprawdzony.'" ';
  5. }
  6.  
  7. $stmt = $db->prepare(
  8. "SELECT * FROM tabela WHERE login=:login AND haslo=:haslo :dodatek_sql "
  9. );
  10. $stmt->bindValue(':login', $login, PDO::PARAM_STR);
  11. $stmt->bindValue(':haslo', $haslo, PDO::PARAM_STR);
  12. $stmt->bindValue(':dodatek_sql', $dodatek_sql, PDO::PARAM_STR); //czy takie coś przejdzie?
  13.  
  14.  
  15. $stmt->execute();
  16. $uzytkownicy = $stmt->fetchAll(PDO::FETCH_ASSOC);
  17.  


trueblue
To możesz tak zrobić:

  1. $stmt = $db->prepare(
  2. "SELECT * FROM tabela WHERE login=:login AND haslo=:haslo AND IF(:dodaj_kod,sprawdzony=:sprawdz,TRUE)"
  3. );
  4. $stmt->bindValue(':login', $login, PDO::PARAM_STR);
  5. $stmt->bindValue(':haslo', $haslo, PDO::PARAM_STR);
  6. $stmt->bindValue(':sprawdz', $sprawdzony, PDO::PARAM_STR);
  7. $stmt->bindValue(':dodaj_kod', $dodaj_kod, PDO::PARAM_INT);
mar1aczi
Cytat(starterrrrr @ 23.08.2016, 01:43:04 ) *
  1. ...
  2. return $result;
  3. mysqli_close($link);
  4. ...

Po "trafieniu" na return już chyba mysqli_close() nie zaskoczy.
Tomplus
Ja korzystam z rozwiązania z tej klasy:
https://github.com/indieteq/indieteq-php-my...-database-class


Dzięki temu parametry do bindValue możesz przekazywać jako parametr funkcji tudzież metody.

  1. $bind = ["firstname"=>"John","id"=>"1"];
  2. $person = $db->query("SELECT * FROM Persons WHERE firstname = :firstname AND id = :id",$bind);
  3. $person = $db->query("SELECT * FROM Persons WHERE firstname = :firstname AND id = :id",array("firstname"=>"John","id"=>"1"));
luis2luis
Cytat(Tomplus @ 26.10.2016, 13:34:53 ) *
Ja korzystam z rozwiązania z tej klasy:
https://github.com/indieteq/indieteq-php-my...-database-class


Dzięki temu parametry do bindValue możesz przekazywać jako parametr funkcji tudzież metody.

  1. $bind = ["firstname"=>"John","id"=>"1"];
  2. $person = $db->query("SELECT * FROM Persons WHERE firstname = :firstname AND id = :id",$bind);
  3. $person = $db->query("SELECT * FROM Persons WHERE firstname = :firstname AND id = :id",array("firstname"=>"John","id"=>"1"));



Fajnie ta klasa wyglada, widze, ze nie aktualizowana 2 lata, ale raczej php 7 nie powinno niczym zaskoczyc nowym w tej kwestii.
Tomplus
Na PHP7 działa bez problemu.
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.