Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][MySQL][PDO] Przepisanie funkcji z MySQL na PDO
Forum PHP.pl > Forum > Przedszkole
Stron: 1, 2
Kshyhoo
Rozpocząłem starcie z PDO smile.gif Postanowiłem przepisać nieco kodu z MySQL na PDO w ramach treningu. Początkowo szło dobrze, ale teraz przegrywam walkę. Połączenie to zdaje się błahostka:
  1. try {
  2. $pdo = new PDO('mysql:host='.$db_host.';dbname='.$db_name.';encoding=utf8', $db_user, $db_pass);
  3. //echo 'Połączenie nawiązane!';
  4. } catch(PDOException $e) {
  5. echo 'Error: ' . $e->getMessage(). "<br/>";
  6. die();
  7. }

Zacząłem od takiej oto funkcji, zwracającej dane usera:
  1. function getUser($id) {
  2. $User = mysql_fetch_array(mysql_query("SELECT * FROM g_users WHERE user=$id"));
  3. if(!empty($User))
  4. $User['data_product'] = mysql_fetch_array(mysql_query("SELECT * FROM g_products WHERE product=".$User['id_product']));
  5. if(empty($User))
  6. $User['function'] = -1;
  7. return $User;
  8. }

  1. function getUser2($id) {
  2. extract($GLOBALS);
  3. $r = $pdo->query("SELECT * FROM g_users WHERE user=$id");
  4. $User = $r->fetch(PDO::FETCH_ASSOC);
  5. if(!empty($User)) {
  6. $r = $pdo->query("SELECT * FROM g_products WHERE product=".$User['id_product']."");
  7. $User['data_product'] = $r->fetch(PDO::FETCH_ASSOC);
  8. }
  9. if(empty($User))
  10. $User['function'] = -1;
  11. return $User;
  12. }

Funkcja zwraca identyczne dane. Czy można to zrobić lepiej?
redeemer
Jeżeli chodzi o PDO to używaj "prepared statements".

1) extract($GLOBALS); - naprawdę?

2)
  1. if(!empty($User)) {
  2. ....
  3. }
  4. if(empty($User))
To można zamienić na if else.

3) te dwa zapytania do bazy na 99% można zastąpić jednym
Kshyhoo
1. Inaczej zgłasza błąd Fatal error: Call to a member function query()
2. No można.
3. Ledwie skleciłem to wink.gif Muszę wpierw załapać PDO.
redeemer
Cytat(Kshyhoo @ 22.03.2014, 14:59:13 ) *
1. Inaczej zgłasza błąd Fatal error: Call to a member function query()
Zgadza się, jest to związane z zakresem zmiennych (funkcja getUser2() nie ma dostępu do zmiennej $pdo).

Opcje:
1) wystarczy: global $pdo; (brzydko)
2) przekaż do funkcji zmienną $pdo jako argument (lepiej)
3) przepisać to na kod obiektowy np. z użyciem wzorca singleton i poczytać o dependency injection (najlepiej) wink.gif
Kshyhoo
1. global $pdo nie działało sad.gif
2. to ma sens
3. a świstak siedzi i zawija w sreberka wink.gif

Mam kolejny problem. Taki kod:
  1. $prods = mysql_query("SELECT * FROM tabela1 LEFT JOIN tabela2 ON prod=prod_id WHERE kat_id=".$User['id_kat']);
  2.  
  3. if(mysql_num_rows($prods) == 0) {

na taki:
  1. $prods = $pdo->query("SELECT * FROM tabela1 LEFT JOIN tabela2 ON prod=prod_id WHERE kat_id=".$User['id_kat']);
  2.  
  3. if ($prods->fetchColumn() === 0) {

To działa, zwraca takie same wyniki, ale czy można lepiej?

Druga rzecz. Kodowanie połączenia. Miałem:
  1. mysql_query("SET NAMES 'utf8'");

W bazie polskie znaki, pliki również UTF-8 a po zmianie na PDO wychodzą krzaki...
Turson
Łącząc się z bazą za pomocą PDO musisz ustalić kodowanie
  1. $db = new PDO('mysql:host=localhost;dbname=xxx', 'user', 'pass', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"))
viking
A w jaki sposób to wywołujesz? Dla mysql możesz bezpośrednio
  1. $connect = new PDO(
  2. "mysql:host=$host;dbname=$db",
  3. $user,
  4. $pass,
  5. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  6. PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
  7. )
  8. );


albo ....exec("set names utf8");
Kshyhoo
W pierwszym poście zamieściłem połączenie z bazą. Czyli coś takiego powinienem użyć?
  1. $pdo = new PDO('mysql:host='.$db_host.';dbname='.$db_name.';encoding=utf8', $db_user, $db_pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"))

Turson
Zobacz czy działa a potem pytaj wink.gif
Kshyhoo
No właśnie, nie działa...
viking
Jaka wersja PHP? Poniżej 5.coś nie działało. Spróbuj jeszcze drugą metodę z exec
Kshyhoo
Nie, nie, mam powyżej 5. Być może to wina tego zapytania ostatniego. Zauważyłem teraz, że ucina mi pierwszy rekord.
Turson
  1. $prods = $pdo->query("SELECT * FROM tabela1 LEFT JOIN tabela2 ON prod=prod_id WHERE kat_id=".$User['id_kat']);
  2. if($prods->rowCount()>0){
  3. while($row=$prods->fetchAll()){
  4. //cos tam
  5. }
  6. }
  7. else echo "Brak wyników";


poza tym powinieneś bindować dane, inaczej stosowanie PDO nie ma sensu
Kshyhoo
To wiem, tak robię. Tylko nigdzie nie mogę znaleźć dobrego artykułu na temat PDO. Nie wiem np., czy ma sens bindowanie zapytań z danymi niepochodzącymi z formularzy i linków...
vonski
Cytat(Turson @ 23.03.2014, 16:22:51 ) *
  1. $prods = $pdo->query("SELECT * FROM tabela1 LEFT JOIN tabela2 ON prod=prod_id WHERE kat_id=".$User['id_kat']);
  2. if($prods->rowCount()>0){
  3. while($row=$prods->fetchAll()){
  4. //cos tam
  5. }
  6. }
  7. else echo "Brak wyników";


while($row = $prods->fetchAll()) ?

Bardziej: while($row=$prods->fetch()){ .. }
Kshyhoo
Tak właśnie miałem, zmieniłem:
  1. while($prod = mysql_fetch_array($prods)) {

na:
  1. while($prod = $prods->fetch()) {

Inaczej nie zwracało wyników.

Nadal nie mam polskich znaków. Tabele w utf8_general_ci.
trueblue
Po połączeniu wykonaj trzy zapytania:
SET character_set_connection=utf8
SET character_set_client=utf8
SET character_set_results=utf8
viking
Więc może te dane nie są w UTF-8 albo nie ustawiasz header. W stopce mam artykuł o PDO. Może Ci pomoże.
Kshyhoo
Czytałem ten artykuł. Wszystko wyświetla się dobrze, z zapytań MySQL, po zmianie na PDO krzaczy.
Turson
Cytat(vonski @ 23.03.2014, 15:28:41 ) *
while($row = $prods->fetchAll()) ?

Bardziej: while($row=$prods->fetch()){ .. }

$dane = $prods->fetchAll();
foreach($dane as $v)

tak zazwyczaj piszę stąd mi się pomyliło.

Kschyhoo, ja zawsze robię tak:
- baza w utf8_polish_ci
- plik w utf8, dokument w utf8
- połączenie z bazą jak podałem
i nigdy nie mam problemu z pl znakami
Kshyhoo
Ja też nie miałem nigdy problemu, a na pewno do czasu PDO ;P Nie mogę dać utf8_polish_ci...
Turson
utf8_general_ci też na pewno działa. Jaki masz?
Kshyhoo
utf8_general_ci

Czy dobrze zrozumiałem. Muszę zamykać każde połączenie (fachowo chyba kursora do obiektu klasy PDOStatement)?
  1. $prods = $pdo->query("SELECT * FROM tabela1 LEFT JOIN tabela2 ON prod=prod_id WHERE kat_id=".$User['id_kat']);
  2. if($prods->rowCount() == 0) {
  3. while($row=$prods->fetchl()) {
  4. // cos tam
  5. }
  6. } else
  7. echo "Brak wyników";
  8.  
  9. $prods->closeCursor();

Chodzi mi o odpowiednik mysql_close();

I jeszcze jedno. Jak mam wyświetlać błędy? tak?
  1. } catch(PDOException $e) {
  2. echo 'Error: ' . $e->getMessage(). "<br/>";
  3. $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
  4. //die();
  5. }
Turson
Jak nie zamkniesz połączenia to nic się stanie. Co do błędów, to można też tak:
  1. $stmt = $pdo->prepare("SELECT....");
  2. if(!$stmt->execute()) print_r($stmt->errorInfo());

działa tylko w przypadku prepare-execute
Kshyhoo
A nie można tego jakoś w konfiguracji wklepać?
viking
Można. Uwzględnieniem ci to specjalnie w poście 7. błędy przechwytuj przez wyjątki. Bo i możesz logowanie ich dodać, i też od razu będziesz w stanie obsłużyć transakcje. Rollback i commit.

A kodowanie nie ma opcji żeby nie działało. Set names + utf8 w edytorze + nagłówki. Jeśli jest inaczej to znaczy ze znaki były np w latin1 błędnie zapisane i działało przez sumę błędów :-)
Dominator
Trochę się tu pogubiłem, z czym masz problem teraz?
I btw. jeśli chcesz mieć polskie znaki zamiast krzaków - spójrz na mój kod. U mnie zawsze są polskie znaki.

Jest to kawałek kodu mojej klasy.

  1. Class Itemshop
  2. {
  3. private $host_db = "localhost";
  4. private $name_db = "test";
  5. private $port_db = "3306";
  6. private $user_db = "";
  7. private $pswd_db = "";
  8. public $conn;
  9. public $error;
  10. public function __construct()
  11. {
  12. $this->Connect();
  13. }
  14. public function Connect()
  15. {
  16. try
  17. {
  18. $pdo = new PDO('mysql:host=localhost;port=3306;dbname=test', '', '', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
  19. $pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  20. if($pdo)
  21. {
  22. $this->conn = $pdo;
  23. return true;
  24. }
  25. }
  26. catch(PDOException $e)
  27. {
  28. echo "Błąd: " . $e->getMessage();
  29. }
  30. }
  31. }
com
  1. $pdo = new PDO('mysql:host='.$db_host.';dbname='.$db_name.';encoding=utf8', $db_user, $db_pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"))


skąd tam Ci się bierze encoding=utf8 ?
Kshyhoo
Cytat(com @ 24.03.2014, 16:49:12 ) *
skąd tam Ci się bierze encoding=utf8 ?

Stąd: wikibooks.org/wiki/PHP/Biblioteka_PDO

Dobra, czas na INSERT. Przykład z MySQL:
  1. mysql_query("INSERT INTO g_a_topics (a_id, title) VALUE (".$User['id_a'].", '".$_POST['title']."')");

i PDO:
  1. $b = $pdo->prepare("INSERT INTO g_a_topics (`id_a`,`title`) VALUES (:id_a, :title)");
  2. $b->bindValue(":id_a", $User['id_a']);
  3. $b->bindValue(":title", $_POST['title']);
  4. $b->execute();
  5.  
  6. $id = $pdo->lastInsertId();

Lub inaczej:
  1. $b = $pdo->prepare("INSERT INTO g_a_topics SET id_a=?, title=?");
  2.  
  3. $b->bindValue(1, $User['id_a']);
  4. $b->bindValue(2, $_POST['title']);
  5. $b->execute();
  6.  
  7. $id = $pdo->lastInsertId();

Nie działają obydwa przykłady.
Turson
Brakuje trzeciego parametru w bindowaniu: PDO::PARAM_STR / PDO::PARAM_INT itd.


INSERT INTO g_a_topics SET id_a=?, title=?
od kiedy tak insert wygląda?
vonski
Ale nie działają w sensie, że zapytanie się wcale nie wykonuje, czy tylko nie zwraca żadnego ID?

  1. var_dump($b->errorInfo());


coś konkretnego pokazuje?

@Turson

Cytat
Brakuje trzeciego parametru w bindowaniu: PDO::PARAM_STR / PDO::PARAM_INT itd.

bindValue przyjmuje domyślnie PDO::PARAM_STR jako trzeci parametr

Cytat
INSERT INTO g_a_topics SET id_a=?, title=?
od kiedy tak insert wygląda?


http://dev.mysql.com/doc/refman/5.6/en/insert.html
Kshyhoo
Właśnie nic nie pokazuje. Strona się przeładowuje. tak ma być?:
  1. $b->bindValue(":id_a", $User['id_a'], PDO::PARAM_INT);
  2. $b->bindValue(":title", $_POST['title'], PDO::PARAM_STR);
  3.  
  4. $b->bindValue(1, $User['id_association'], PDO::PARAM_INT);
  5. $b->bindValue(2, $_POST['title'], PDO::PARAM_STR);

Przykłady znalazłem: PHP_MYSQL_PDO_-_kompendium www.mpcforum.pl/topic/876926-tut-poradnik-pdo/
vonski
A masz AUTO_INCREMENT ustawione na kolumnie `id_a`? Bo lastInsertId() zadziała tylko dla kolumn AUTO_INCEREMENT.

[edit]
To zapewne literówka, ale tak gwoli ścisłości... smile.gif

W przykładzie MYSQL wstawiasz do kolumny o nazwie `a_id`, a w PDO do kolumny `id_a`

Z tym że jeśli kolumna by nie istniała to errorInfo() musiałby jakiś konkretny błąd pokazać...
Kshyhoo
Tak mam, problem, że w ogóle nie dodaje nic do bazy.

OK, znalazłem babola. id_a != a_id smile.gif
vonski
I to:

  1. var_dump($b->errorInfo());


nie pokazuje żadnego błędu? Tzn. pierwszy element tablicy ma same zera? Z tym że to ma być wywołane zaraz PO execute() i oczywiście chodzi mi o PDOStatement::errorInfo(), nie o PDO::errorInfo().

[edit]
a jednak smile.gif
Kshyhoo
Właśnie nie wiem dlaczego nie zwraca mi żadnych błędów. Musiałem wyciąć kawałek kody i przenieść do innego pliku i dopiero wtedy wywaliło błąd.

Jak mam dodać datę w bindowaniu?
  1. $p->bindValue(":data", now(), PDO::PARAM_INT);


Binduje się wartości przekazywane do PDO a nie funkcje, już wiem wink.gif
slashynsky
data np.strtotime i robisz PARAM_STR nie int, int-em bedzie timestamp
viking
A gdybyś się zastanawiał, tak jak ja kiedyś, co właściwie robi PDO::PARAM_* masz odpowiedź http://stackoverflow.com/questions/833510/...ow-does-it-work Jak widać niewiele robi.
Turson
Cytat(Kshyhoo @ 24.03.2014, 22:53:41 ) *
Właśnie nie wiem dlaczego nie zwraca mi żadnych błędów. Musiałem wyciąć kawałek kody i przenieść do innego pliku i dopiero wtedy wywaliło błąd.

Jak mam dodać datę w bindowaniu?
  1. $p->bindValue(":data", now(), PDO::PARAM_INT);


Binduje się wartości przekazywane do PDO a nie funkcje, już wiem wink.gif

NOW() traktuj jako STR a nie INT no i możesz bezpośrednio w zapytaniu NOW dać bez bindowania
nospor
Cytat
no i możesz bezpośrednio w zapytaniu NOW dać bez bindowania
On nie moze.... on MUSI. Funkcji mysql nie da sie zbindowac.
Kshyhoo
Mam problem z takim kodem:
  1. $atts = mysql_query("SELECT *
  2. FROM g_atts
  3. INNER JOIN g_ts
  4. ON target=t
  5. INNER JOIN g_events e
  6. ON e.number=att
  7. WHERE (e.type = 10 OR e.type = 11)
  8. AND e.t_id=".$User['id_t']);
  9. if(mysql_num_rows($atts) > 0) {
  10. // ...
  11. $ref = $atts[0]['finish'];
  12. while($att = mysql_fetch_array($atts)) {

Rozumiem, że dostawałem tablicę. A tera jak mam to sprawdzić? Jak robię tak:
  1. $r = $pdo->query("SELECT *
  2. FROM g_att
  3. INNER JOIN g_ts
  4. ON target=t
  5. INNER JOIN g_events e
  6. ON e.number=att
  7. WHERE (e.type = 10 OR e.type = 11)
  8. AND e.town_id=".$User['id_t']);
  9. $atts = $r->fetch(PDO::FETCH_ASSOC);
  10. if($atts) {
  11. //
  12. $ref = $atts[0]['finish'];
  13. while ($att = $atts->fetch()) {

To var_dump($attacks); zwraca bool(false).
Turson
O co w zasadzie pytasz? Odpowiednikiem mysql_num_rows jest $r->rowCount()
var_dump($attacks); zwraca bool(false). - nie widzę $attacks
Turson
Cytat
Mam problem z takim kodem:

Pisz proszę jak na opiekuna przystało, a nie "mam problem, pomóżcie"
Kshyhoo
Źle wkleiłem, poprawione smile.gif
Chodzi o to, że w 1 zapytaniu zwraca np:
resource(3) of type (mysql result) Resource id #3
a w PDO zwraca zapytanie.

Napisałem, że dostawałem tablicę, to znaczyło by, że teraz jej nie otrzymuję ;p
Turson
  1. $r = $pdo->query("SELECT *
  2. FROM g_att
  3. INNER JOIN g_ts
  4. ON target=t
  5. INNER JOIN g_events e
  6. ON e.number=att
  7. WHERE (e.type = 10 OR e.type = 11)
  8. AND e.town_id=".$User['id_t']);
  9.  
  10. if($r->rowCount()>0) {
  11. $tablica = $r->fetchAll(PDO::FETCH_ASSOC);
  12. var_dump($tablica);
  13. foreach($tablica as $v){
  14. //
  15. }
  16. }
  17. else echo "Brak";


questionmark.gif
Kshyhoo
Czyli to:
  1. $tt = mysql_fetch_array(mysql_query("SELECT name FROM g_ts WHERE t=".$_GET['att']." LIMIT 1"));
  2. $tt = $tt[0];

Mam zapisać tak:
  1. $r = $pdo->query("SELECT name FROM g_ts WHERE t=".$_GET['att']." LIMIT 1"));
  2. $tt = $r->fetchAll(PDO::FETCH_ASSOC);


questionmark.gif
Turson
Tak, w $tt będziesz miał wszystkie wyniki, choć w przypadku "LIMIT 1" samo fetch(). Nawias za dużo skopiowałeś w zapytaniu smile.gif
viking
Chyba musisz trochę do dokumentacji przysiąść, w szczególności do zwracanych typów smile.gif
http://www.php.net/manual/en/class.pdo.php
Zwróć uwagę że masz metody ogólne obiektu PDO które w obsługują adapter db czyli transakcje, błędy i przygotowanie zapytań. Oraz PDOStatement które to ma za zadanie obsługę już samego zapytania (kursora - co za tym idzie wyświetlania wyników, bindowanie parametrów). I np za dokumentacją:
  1. public [b]PDOStatement[/b] prepare ( string $statement [, array $driver_options = array() ] )
  2. public [b]PDOStatement[/b] query ( string $statement )

więc jeśli gdzieś masz query to musisz stosować metody z http://www.php.net/manual/en/class.pdostatement.php

2 uwagi. Spróbuj używać wyjątków albo dla całej aplikacji, albo chociaż samego zapytania bo wcześniejsze problemy wynikały w dużej mierze z ich braku. PDOException nie było nigdzie łapane, nie wiedziałeś co się dzieje. Nie wiem czy podajesz tylko do wglądu ale nie używasz prepare więc te zapytania nie są ani bezpieczne, ani nie ma żadnych zalet nad zwykłym mysql_.
I w sumie trzecia jeszcze. http://www.php.net/manual/en/pdostatement.rowcount.php

Cytat
PDOStatement::rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.

If the last SQL statement executed by the associated PDOStatement was a SELECT statement, some databases may return the number of rows returned by that statement. However, this behaviour is not guaranteed for all databases and should not be relied on for portable applications.
Kshyhoo
  1. $r = $pdo->query("SELECT *
  2. FROM g_att
  3. INNER JOIN g_ts
  4. ON target=t
  5. INNER JOIN g_events e
  6. ON e.number=att
  7. WHERE (e.type = 10 OR e.type = 11)
  8. AND e.town_id=".$User['id_t']);
  9.  
  10. if($r->rowCount()>0) {
  11. $tablica = $r->fetchAll(PDO::FETCH_ASSOC);
  12. var_dump($tablica);
  13. foreach($tablica as $v){
  14. //
  15. }
  16. }
  17. else echo "Brak";

Jak takie cudo miałbym zapisać w pętli while? Do czego to porównać?


Nie kumam tego przykładu, konkretnie:
  1. // przygotowanie zapytania
  2. $zapytanie = $baza->prepare("SELECT login, email FROM gracze WHERE level = :poziom AND klasa= :klasa");
  3. // filtracja wskazanych danych
  4. $zapytanie->bindValue(':poziom', $_POST['poziom'], PDO::PARAM_INT);
  5. $zapytanie->bindValue(':klasa', trim($_GET['klasa']), PDO::PARAM_STR);
  6. // właściwe wykonanie
  7. $zapytanie->execute();
  8.  
  9. if ($gracze->rowCount() > 0) {
  10. while ($gracz = $zapytanie->fetch()) {
  11. echo 'Gracz: '.$gracz['login'].' ma adres emaill: '.$gracz['email'].'<br/>';
  12. }
  13. } else echo 'Brak graczy o podanych parametrach..';

if ($gracze - skąd wytrzepał $gracze?

Przecież to da:
Notice: Undefined variable: gracze in
A w efekcie:
Fatal error: Call to a member function rowCount() on a non-object in
Turson
Zamiast $gracze powinno być $zapytanie, widocznie pomyłka
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.