2009-11-23 10 views
113

W PHP, podczas uzyskiwania dostępu do bazy danych MySQL z PDO z parametryzowanym zapytaniem, w jaki sposób można sprawdzić ostatnie zapytanie (po zastąpieniu wszystkich tokenów)?W PHP z PDO, jak sprawdzić ostateczne zapytanie parametryczne SQL?

Czy istnieje sposób sprawdzenia, co naprawdę jest wykonywane przez bazę danych?

+2

Naprawdę szkoda, że ​​nie było sposobu, aby to zrobić. Przez jakiś czas mnie to dręczyło. –

+1

Dla PHP> = 5.1, spójrz na http://www.php.net/manual/en/pdostatement.debugdumpparams.php – Mawg

+1

Istnieje błąd w 'debugDumpParams()' - żadne wartości nie są zawarte w ouput.Jedynym sposobem (łatwego) sprawdzenia zapytań wykonywanych przez 'mysql' jest tymczasowe włączenie logu w my.cnf (h/t do @JB Hurteaux) –

Odpowiedz

49

Więc myślę, że w końcu odpowiem na moje własne pytanie, aby mieć pełne rozwiązanie dla płyty. Ale muszę podziękować Benowi Jamesowi i Kailashowi Badu, którzy dostarczyli wskazówek na ten temat.

Krótka odpowiedź
Jak wspomniano Ben James: NO.
Pełne zapytanie SQL nie istnieje po stronie PHP, ponieważ zapytanie za pomocą tokenów i parametry są wysyłane oddzielnie do bazy danych. Tylko po stronie bazy danych istnieje pełne zapytanie.

Nawet próba stworzenia funkcji zastępującej tokeny po stronie PHP nie gwarantowałaby, że proces wymiany jest taki sam jak w SQL (podstępne rzeczy, takie jak token-type, bindValue vs bindParam, ...)

Obejście
To gdzie ja rozwinąć odpowiedź Kailash Badu za. Logując wszystkie zapytania SQL, widzimy, co naprawdę działa na serwerze. z MySQL, można to zrobić poprzez aktualizację my.cnf (lub my.ini w moim przypadku z serwerem Wamp) i dodanie linii jak:

log=[REPLACE_BY_PATH]/[REPLACE_BY_FILE_NAME] 

Tylko nie uruchomić to w produkcji !! !

+1

Pamiętaj, aby zrestartować 'mysql' dla zmian w' my.cnf' aby zacząć działać. Po uruchomieniu zapytania pamiętaj o skomentowaniu linii dziennika i ponownie uruchom 'mysql', aby zatrzymać rejestrowanie. –

0

Nie wierzę, że możesz, choć mam nadzieję, że ktoś mi się nie uda.

Wiem, że można wydrukować zapytanie, a jego metoda toString pokaże sql bez zamiany. To może być przydatne, gdy budujesz złożone zapytania, ale nie daje pełnego zapytania z wartościami.

26

Stosowanie przygotowanych instrukcji z parametrami wartości nie jest po prostu kolejnym sposobem dynamicznego tworzenia ciągu znaków SQL. Utworzoną instrukcję tworzy się w bazie danych, a następnie przesyła same wartości parametrów.

To, co prawdopodobnie zostanie wysłane do bazy danych, to PREPARE ..., następnie SET ..., a na koniec EXECUTE ....

Nie można uzyskać ciągów SQL takich jak SELECT * FROM ..., nawet jeśli dałoby to równoważne wyniki, ponieważ żadne takie zapytanie nie zostało faktycznie wysłane do bazy danych.

+1

Zaakceptowanie tego na razie, ponieważ ma to sens. To nie jest zbyt wygodne do debugowania ... –

+2

Czy istnieje sposób, abyśmy mogli zobaczyć "strumień" instrukcji sql, które faktycznie są wykonywane? Może nadal może być pomocna, lepsza niż nic. –

+0

'$ stmt-> debugDumpParams();' powinien być blisko. –

1

Co zrobiłem, aby wydrukować że rzeczywista zapytanie jest trochę skomplikowane, ale działa :)

W metodzie przypisujące zmienne do mojego rachunku mam inną zmienną, która wygląda trochę jak ten:

$this->fullStmt = str_replace($column, '\'' . str_replace('\'', '\\\'', $param) . '\'', $this->fullStmt); 

Gdzie:
$column jest mój znak
$param jest rzeczywista wartość jest przypisany do tokena
$this->fullStmt jest mój druk oświadczenie tylko zastąpionych tokenów

To, co robi, to po prostu zamienić tokeny na wartości, gdy dzieje się prawdziwe przypisanie PDO.

Mam nadzieję, że cię nie pomyliłem i przynajmniej wskazałem ci właściwy kierunek.

+0

Tak, dziękuję. Ja również z funkcji niestandardowej, aby ręcznie zastąpić tokeny po widząc odpowiedź od Ben James. Niezbyt wygodne, gdy istnieje kilka żetonów, ale może istnieć sposób na zautomatyzowanie tego (jeśli mamy dostęp do wszystkich utworzonych powiązań) i utworzenie ogólnej funkcji. Z drugiej strony to, czego chcę, to tak naprawdę zapytanie generowane przed wykonaniem. Utworzenie mojej własnej funkcji nie gwarantuje tego, że otrzymam taki sam wynik (np. Biorąc pod uwagę wstawione cytaty dotyczące parametrów String ...) –

9

Sprawdzam dziennik zapytań, aby zobaczyć dokładne zapytanie, które zostało wykonane jako gotowe oświadczenie.

17

Być może będziesz w stanie użyć PDOStatement->debugDumpParams. Zobacz the PHP documentation.

+3

Dobra odpowiedź, ale wyświetlanie wartości parametrów [może być potrzebna łatka] (http://stackoverflow.com/a/3656529/819417). –

+0

+1 To prawdopodobnie powinno być zaakceptowane jako odpowiedź. Pozwala na mieszanie SQL z innymi ścieżkami debugowania z PHP, zamiast szukać w kilku miejscach. – Mawg

4

Początkowo unikałem włączania logowania do monitorowania PDO, ponieważ myślałem, że będzie to kłopot, ale nie jest wcale trudne. Nie trzeba ponownie uruchomić MySQL 5.1.9 (po):

Wykonaj ten SQL w phpMyAdmin lub innym środowisku, gdzie może masz wysokie db przywileje:

SET GLOBAL general_log = 'ON'; 

w terminalu, ogon swój dziennik plik. Kopalnia była tutaj:

>sudo tail -f /usr/local/mysql/data/myMacComputerName.log 

Możesz wyszukać swoje mysql plików z tego terminalu komendę:

>ps auxww|grep [m]ysqld 

stwierdziliśmy, że PDO ucieka wszystko, więc nie można napisać

$dynamicField = 'userName'; 
$sql = "SELECT * FROM `example` WHERE `:field` = :value"; 
$this->statement = $this->db->prepare($sql); 
$this->statement->bindValue(':field', $dynamicField); 
$this->statement->bindValue(':value', 'mick'); 
$this->statement->execute(); 

Ponieważ tworzy:

SELECT * FROM `example` WHERE `'userName'` = 'mick' ; 

Co nie spowodowało błędu, tylko pusty wynik. Zamiast tego potrzebne do korzystania

$sql = "SELECT * FROM `example` WHERE `$dynamicField` = :value"; 

dostać

SELECT * FROM `example` WHERE `userName` = 'mick' ; 

Po zakończeniu wykonywania:

SET GLOBAL general_log = 'OFF'; 

albo dzienniki dostanie ogromne.

+2

Stworzyłeś więc zapytanie otwarte na SQL injection, gratulacje :) –

+4

Właściwie nie, po pierwsze pdo nie ma możliwości ustawienia kolumn dynamicznych w ten sposób. To najlepszy sposób na zrobienie tego. Po drugie, dynamiczne ustawianie pól w ten sposób: 'dynamicField = 'userName'' nie pozostawia miejsca na iniekcję. Dopóki sprawdzasz nazwy kolumn na białej liście, nie można wprowadzić tej metody budowania sql. – Louis

-1

Myślę, że najprostszym sposobem zobaczenia końcowego tekstu zapytania podczas korzystania z pdo jest wygenerowanie specjalnego błędu i wyświetlenie komunikatu o błędzie. Nie wiem jak to zrobić, ale gdy robię błąd sql w strukturze yii, który używa pdo, mogę zobaczyć tekst zapytania: